diff --git a/.gitmodules b/.gitmodules index 0c3e3cf..070d332 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,15 +4,3 @@ [submodule "lib/DeathHandler"] path = lib/DeathHandler url = https://github.com/vmarkovtsev/DeathHandler.git -[submodule "lib/Catch"] - path = lib/Catch - url = https://github.com/philsquared/Catch.git -[submodule "lib/clooneljump"] - path = lib/clooneljump - url = https://bitbucket.org/King_DuckZ/clooneljump.git -[submodule "lib/better-enums"] - path = lib/better-enums - url = https://github.com/aantron/better-enums -[submodule "lib/tmxlite"] - path = lib/tmxlite - url = https://github.com/fallahn/tmxlite.git diff --git a/CMakeLists.txt b/CMakeLists.txt index f9d2048..cd07e60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,21 @@ cmake_minimum_required(VERSION 3.2) -project(mycurry_toplevel CXX) +project(mycurry CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/include") include(TargetArch) include(FindPkgConfig) -include(CTest) + +set(common_gcc_flags "-Wall -Wextra -pedantic -Wconversion") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags} -O0") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${common_gcc_flags}") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags} -O0") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${common_gcc_flags}") option(CURRY_FORCE_OPENGLES "Try to chose the openGL ES renderer if available. Enable this on Raspberry Pi" OFF) option(CURRY_RASPBERRY_PI "Compile for Raspberry Pi" OFF) set(MYCURRY_RESOURCES_PATH "${CMAKE_CURRENT_SOURCE_DIR}" CACHE STRING "Path to the program's resources") -set(CLOONEL_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/clooneljump") target_architecture(TARGET_ARCH) message (STATUS "Target architecture: ${TARGET_ARCH}") @@ -30,6 +34,9 @@ if (CURRY_FORCE_OPENGLES OR CURRY_RASPBERRY_PI) endif(CURRY_RASPBERRY_PI) endif (CURRY_FORCE_OPENGLES OR CURRY_RASPBERRY_PI) +PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) +PKG_SEARCH_MODULE(SDL2IMAGE REQUIRED SDL2_image>=2.0.0) +find_package(PNG REQUIRED) find_package(Boost 1.55.0 REQUIRED) if (CURRY_RASPBERRY_PI) @@ -44,33 +51,71 @@ if (CURRY_RASPBERRY_PI) ) endif (CURRY_RASPBERRY_PI) +add_executable(${PROJECT_NAME} + src/csvloader.cpp + src/main.cpp + src/sdlmain.cpp + src/ingamescene.cpp + src/sizenotifiable.cpp + src/sizeratio.cpp + src/gamescenebase.cpp + src/worldgrid.cpp + src/worldviewport.cpp + src/inputbag.cpp + src/tileiterator.cpp + src/texture.cpp + src/movingobject.cpp + src/character.cpp + src/rect_to_sdl.cpp + src/worldsizenotifiable.cpp + src/worlditems.cpp + src/moveable.cpp + src/singlecoordinate.cpp +) + +target_include_directories(${PROJECT_NAME} SYSTEM + PRIVATE ${SDL2_INCLUDE_DIR} + PRIVATE ${SDL2IMAGE_INCLUDE_DIRS} + PRIVATE ${PNG_INCLUDE_DIRS} + PRIVATE ${Boost_INCLUDE_DIRS} + PRIVATE lib/tree-2.81/src +) +target_include_directories(${PROJECT_NAME} + PRIVATE src + PRIVATE lib/vectorwrapper/include + PRIVATE lib/DeathHandler + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE ${SDL2_LIBRARIES} + PRIVATE ${SDL2IMAGE_LIBRARIES} + PRIVATE ${PNG_LIBRARIES} +) + if (CURRY_RASPBERRY_PI) target_link_libraries(${PROJECT_NAME} PRIVATE bcm_host ) endif(CURRY_RASPBERRY_PI) -configure_file(src/${PROJECT_NAME}Config.h.in ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.h) +target_compile_features(${PROJECT_NAME} + PRIVATE cxx_nullptr + PRIVATE cxx_range_for + PRIVATE cxx_lambdas + PRIVATE cxx_decltype_auto + PRIVATE cxx_defaulted_functions + PRIVATE cxx_deleted_functions + PRIVATE cxx_auto_type + PRIVATE cxx_defaulted_move_initializers + PRIVATE cxx_noexcept + PRIVATE cxx_rvalue_references +) -set(common_gcc_flags -Wall -Wextra -pedantic -Wconversion -ffast-math) - -add_library(${PROJECT_NAME} INTERFACE) -target_compile_options(${PROJECT_NAME} INTERFACE ${common_gcc_flags}) target_compile_definitions(${PROJECT_NAME} - INTERFACE $<$:KAK_DEBUG> - INTERFACE VWR_OUTER_NAMESPACE=curry -) -target_include_directories(${PROJECT_NAME} - INTERFACE lib/kakoune - INTERFACE lib/better-enums + PRIVATE ${PNG_DEFINITIONS} + PRIVATE VWR_WITH_IMPLICIT_CONVERSIONS=1 + PRIVATE VWR_EXTRA_ACCESSORS ) -add_subdirectory(lib/clooneljump/src/cloonelgraphics) -add_subdirectory(lib/tmxlite/tmxlite) -add_subdirectory(src/gamelib) -add_subdirectory(src/standalone) - -if (BUILD_TESTING) - set(CATCH_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/Catch") - add_subdirectory(test/unit) -endif() +configure_file(src/${PROJECT_NAME}Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.h) diff --git a/docs/assembly_references.txt b/docs/assembly_references.txt deleted file mode 100644 index 5f06673..0000000 --- a/docs/assembly_references.txt +++ /dev/null @@ -1,26 +0,0 @@ -EFLAGS bit meaning -http://reverseengineering.stackexchange.com/a/9222 - -GCC inline assembly -http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html - -Popping the FPU stack -http://stackoverflow.com/a/33575875/768582 - -Decoding a sample snippet of asm -http://stackoverflow.com/questions/9186150/decoding-and-understanding-assembly-code - -GNU assembler examples -http://cs.lmu.edu/~ray/notes/gasexamples/ - -GCC function attributes (see "naked") -https://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/Function-Attributes.html - -Fast floating point sign -http://stackoverflow.com/a/2508911/768582 - -AMD assembly reference -http://developer.amd.com/wordpress/media/2012/10/26569_APM_v51.pdf - -Moving values between SSE and FPU -http://stackoverflow.com/questions/37567154/intel-x86-64-assembly-how-to-move-between-x87-and-sse2-calculating-arctangent#37573264 diff --git a/docs/old_code/asm/x86_64/fsgn.s b/docs/old_code/asm/x86_64/fsgn.s deleted file mode 100644 index ba827a0..0000000 --- a/docs/old_code/asm/x86_64/fsgn.s +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2016, 2017 Michele "King_DuckZ" Santullo - -# This file is part of MyCurry. - -# MyCurry is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# MyCurry is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with MyCurry. If not, see . -# - -.data -minus1: .float -1.0 - -.global fsgn_asm - -.text -fsgn_asm: - subq $24,%rsp - movss %xmm0,(%rsp) - fldz - flds (%rsp) - fcomp - - fstsw %ax - sahf - - fld1 - fld minus1 - - fcmovnbe %st(1),%st - fcmove %st(2),%st - - fstps (%rsp) - fninit - movss (%rsp),%xmm0 - - #xorpd %xmm0,%xmm0 - addq $24,%rsp - ret diff --git a/docs/old_code/fsgn_timing.cpp b/docs/old_code/fsgn_timing.cpp deleted file mode 100644 index 1a1886f..0000000 --- a/docs/old_code/fsgn_timing.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "fsgn_timing.hpp" -#include "fsgn.hpp" -#if defined(FSGN_WITH_TIMING) -# include -# include -# include -# include -# include -#endif - -namespace curry { -#if defined(FSGN_WITH_TIMING) - void do_fsgn_timing() { - constexpr const auto count = 1000000U; - std::minstd_rand rand; - std::vector inputs(count); - std::generate(inputs.begin(), inputs.end(), [&](){ - return static_cast(rand()) - static_cast(rand.max()) / 2.0f; - }); - - //fast_fsgn - { - float result = 0.0f; - - auto t_start = std::chrono::high_resolution_clock::now(); - for (auto z = 0U; z < count; ++z) { - result += fast_fsgn(inputs[z]); - } - auto t_end = std::chrono::high_resolution_clock::now(); - - std::cout << "fast_fsgn result: " << result << " in " << - std::chrono::duration(t_end - t_start).count() << '\n'; - } - - //fsgn_asm - { - float result = 0.0f; - - auto t_start = std::chrono::high_resolution_clock::now(); - for (auto z = 0U; z < count; ++z) { - result += fsgn_asm(inputs[z]); - } - auto t_end = std::chrono::high_resolution_clock::now(); - - std::cout << "fsgn_asm result: " << result << " in " << - std::chrono::duration(t_end - t_start).count() << '\n'; - } - - //fsgn - { - float result = 0.0f; - - auto t_start = std::chrono::high_resolution_clock::now(); - for (auto z = 0U; z < count; ++z) { - result += fsgn(inputs[z]); - } - auto t_end = std::chrono::high_resolution_clock::now(); - - std::cout << "fsgn result: " << result << " in " << - std::chrono::duration(t_end - t_start).count() << '\n'; - } - } -#endif -} //namespace curry diff --git a/docs/old_code/fsgn_timing.hpp b/docs/old_code/fsgn_timing.hpp deleted file mode 100644 index 7843658..0000000 --- a/docs/old_code/fsgn_timing.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#define FSGN_WITH_TIMING - -namespace curry { -#if defined(FSGN_WITH_TIMING) - void do_fsgn_timing(); -#endif -} //namespace curry diff --git a/gdb/vectorwrapper.py b/gdb/vectorwrapper.py deleted file mode 100644 index 1db58a6..0000000 --- a/gdb/vectorwrapper.py +++ /dev/null @@ -1,72 +0,0 @@ - # - # Copyright 2015-2017 Michele "King_DuckZ" Santullo - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - -import gdb.printing - -#NOTE: -#This pretty-printer has been written for vectorwrapper + std::array. -#You will have to customize it if your wrapped type is different. - -class VectorWrapperStdArrPrinter(object): - "Print values in a VectorWrapper" - - class _iterator(object): - def __init__(self, start, size): - self.item = start - self.pos = 0 - self.size = size - - def __iter__(self): - return self - - def __next__(self): - if self.pos == self.size: - raise StopIteration - elt = self.item.dereference() - self.item = self.item + 1 - self.pos = self.pos + 1 - return str(elt) - - def __init__(self, val): - self.val = val - self.dimensions = int(val.type.template_argument(1)) - - def to_string(self): - #get the scalar[n] value - stdarray_elems = self.val['m_wrapped']['_M_elems'] - #get the actual scalar type - elem_type = self.val['m_wrapped'].type.template_argument(0) - #cast scalar[n] to scalar* - ptr = stdarray_elems.address.cast(elem_type.pointer()) - #iterate over the values in scalar* and str() them - retval = "vec" + str(self.dimensions) + "<" + \ - ", ".join( - str(itm) for itm in self._iterator(ptr, self.dimensions) - ) + ">" - return retval - - def display_hint(self): - return 'string' - -def build_pretty_printer(): - pp = gdb.printing.RegexpCollectionPrettyPrinter(__name__) - #add your namespace before 'vwr' if you're using a custom one - pp.add_printer('vwr', '^curry::vwr::Vec - -namespace Kakoune -{ - -struct RefCountable -{ - int refcount = 0; - virtual ~RefCountable() = default; -}; - -struct RefCountablePolicy -{ - static void inc_ref(RefCountable* r, void*) noexcept { ++r->refcount; } - static void dec_ref(RefCountable* r, void*) { if (--r->refcount == 0) delete r; } - static void ptr_moved(RefCountable*, void*, void*) noexcept {} -}; - -template -struct RefPtr -{ - RefPtr() = default; - explicit RefPtr(T* ptr) : m_ptr(ptr) { acquire(); } - ~RefPtr() { release(); } - RefPtr(const RefPtr& other) : m_ptr(other.m_ptr) { acquire(); } - RefPtr(RefPtr&& other) - noexcept(noexcept(std::declval().moved(nullptr))) - : m_ptr(other.m_ptr) { other.m_ptr = nullptr; moved(&other); } - - RefPtr& operator=(const RefPtr& other) - { - if (other.m_ptr != m_ptr) - { - release(); - m_ptr = other.m_ptr; - acquire(); - } - return *this; - } - - RefPtr& operator=(RefPtr&& other) - { - release(); - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - moved(&other); - return *this; - } - - RefPtr& operator=(T* ptr) - { - if (ptr != m_ptr) - { - release(); - m_ptr = ptr; - acquire(); - } - return *this; - } - - [[gnu::always_inline]] - T* operator->() const { return m_ptr; } - [[gnu::always_inline]] - T& operator*() const { return *m_ptr; } - - [[gnu::always_inline]] - T* get() const { return m_ptr; } - - [[gnu::always_inline]] - explicit operator bool() const { return m_ptr; } - - void reset(T* ptr = nullptr) - { - if (ptr == m_ptr) - return; - release(); - m_ptr = ptr; - acquire(); - } - - friend bool operator==(const RefPtr& lhs, const RefPtr& rhs) { return lhs.m_ptr == rhs.m_ptr; } - friend bool operator!=(const RefPtr& lhs, const RefPtr& rhs) { return lhs.m_ptr != rhs.m_ptr; } - -private: - T* m_ptr = nullptr; - - [[gnu::always_inline]] - void acquire() - { - if (m_ptr) - Policy::inc_ref(m_ptr, this); - } - - [[gnu::always_inline]] - void release() - { - if (m_ptr) - Policy::dec_ref(m_ptr, this); - } - - [[gnu::always_inline]] - void moved(void* from) - noexcept(noexcept(Policy::ptr_moved(nullptr, nullptr, nullptr))) - { - if (m_ptr) - Policy::ptr_moved(m_ptr, from, this); - } -}; - -} - -#endif // ref_ptr_hh_INCLUDED diff --git a/lib/kakoune/safe_ptr.hh b/lib/kakoune/safe_ptr.hh deleted file mode 100644 index 36aa80d..0000000 --- a/lib/kakoune/safe_ptr.hh +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef safe_ptr_hh_INCLUDED -#define safe_ptr_hh_INCLUDED - -// #define SAFE_PTR_TRACK_CALLSTACKS - -//King_DuckZ: -#include -#define kak_assert(a) assert(a) - -//#include "assert.hh" -#include "ref_ptr.hh" - -#include -#include - -#ifdef SAFE_PTR_TRACK_CALLSTACKS -#include "backtrace.hh" -#include "vector.hh" -#include -#endif - -namespace Kakoune -{ - -// *** SafePtr: objects that assert nobody references them when they die *** - -class SafeCountable -{ -public: -#ifdef KAK_DEBUG - SafeCountable() : m_count(0) {} - SafeCountable (SafeCountable&&) : m_count(0) {} - ~SafeCountable() - { - kak_assert(m_count == 0); - #ifdef SAFE_PTR_TRACK_CALLSTACKS - kak_assert(m_callstacks.empty()); - #endif - } - -private: - friend struct SafeCountablePolicy; - #ifdef SAFE_PTR_TRACK_CALLSTACKS - struct Callstack - { - Callstack(void* p) : ptr(p) {} - void* ptr; - Backtrace bt; - }; - - mutable Vector m_callstacks; - #endif - mutable int m_count; -#endif -}; - -struct SafeCountablePolicy -{ -#ifdef KAK_DEBUG - static void inc_ref(const SafeCountable* sc, void* ptr) noexcept - { - ++sc->m_count; - #ifdef SAFE_PTR_TRACK_CALLSTACKS - sc->m_callstacks.emplace_back(ptr); - #else - static_cast(ptr); - #endif - } - - static void dec_ref(const SafeCountable* sc, void* ptr) noexcept - { - --sc->m_count; - kak_assert(sc->m_count >= 0); - #ifdef SAFE_PTR_TRACK_CALLSTACKS - auto it = std::find_if(sc->m_callstacks.begin(), sc->m_callstacks.end(), - [=](const SafeCountable::Callstack& cs) { return cs.ptr == ptr; }); - kak_assert(it != sc->m_callstacks.end()); - sc->m_callstacks.erase(it); - #else - static_cast(ptr); - #endif - } - - static void ptr_moved(const SafeCountable* sc, void* from, void* to) noexcept - { - #ifdef SAFE_PTR_TRACK_CALLSTACKS - auto it = std::find_if(sc->m_callstacks.begin(), sc->m_callstacks.end(), - [=](const SafeCountable::Callstack& cs) { return cs.ptr == from; }); - kak_assert(it != sc->m_callstacks.end()); - it->ptr = to; - #else - static_cast(sc); - static_cast(from); - static_cast(to); - #endif - } -#else - static void inc_ref(const SafeCountable*, void*) noexcept {} - static void dec_ref(const SafeCountable*, void*) noexcept {} - static void ptr_moved(const SafeCountable*, void*, void*) noexcept {} -#endif -}; - -template -using SafePtr = RefPtr; - -} - -#endif // safe_ptr_hh_INCLUDED diff --git a/lib/tmxlite b/lib/tmxlite deleted file mode 160000 index 3934199..0000000 --- a/lib/tmxlite +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3934199e22d68a3a1e7c72049b5f6e85559e99dc diff --git a/lib/tree-2.81/ChangeLog b/lib/tree-2.81/ChangeLog new file mode 100644 index 0000000..9b05100 --- /dev/null +++ b/lib/tree-2.81/ChangeLog @@ -0,0 +1,391 @@ +2011-08-23 Kasper Peeters + + * Brown paper bag release 2.81. + +2011-08-23 Kasper Peeters + + * Released 2.8 + + * License updated. + +2010-12-24 Kasper Peeters + + * Added a number of asserts to trip when passing invalid iterators + to append_child/prepend_child members. + +2010-03-24 Kasper Peeters + + * Released 2.70 + + * Fixed handling of std::allocator to make it more likely to work + on non-GNU platforms. + +2009-12-28 Kasper Peeters + + * Fixed the operator= return type and handled self-assignment + (thanks to Xinlin Cao for the fix). + +2009-05-05 Kasper Peeters + + * Released 2.65 + + * Added skip_children(bool), fixed post-increment/decrement + operators to not refer to 'n' anymore. + +2009-04-03 Kasper Peeters + + * Added a sibling member for quick access to the n-th sibling + (thanks to Adam Connell for sending the patch). + +2009-03-06 Kasper Peeters + + * Fixed an old bug in compare_nodes (pointed out to me in 2005 but + never fixed properly...) + +2008-08-28 Kasper Peeters + + * Released 2.62 + + * Changed the behaviour of max_depth() so that it returns -1 for + an empty tree, instead of bailing out with an error (strictly + speaking max_depth should be undefined...). + +2008-08-26 Kasper Peeters + + * Released 2.61 + + * Fixed a bug in max_depth() which would fail on trees with more + than one head node (thanks to Marc Noirot for pointing this out). + +2008-08-23 Kasper Peeters + + * Released 2.60 + + * Fixed several problems with fixed_depth iterators: iterating + beyond the top node now disabled and operator-- fixed. + +2008-07-25 Kasper Peeters + + * Made 'child()' static. + +2008-07-20 Kasper Peeters + + * Released 2.54 + + * Changed size() members to return size_t instead of unsigned int. + + * Changed behaviour of operator++ for leaf_iterator so that it can + be used in situations where new leaves get added during iteration. + +2008-06-30 Kasper Peeters + + * Released 2.52 + + * Made depth member function static so it can be used independent + of an actual tree, and added a version with two iterators to + measure depths relative to a different node. + +2008-02-28 Kasper Peeters + + * Released 2.51 + + * Added a top node to leaf_iterators, so that they can be + instructed to iterate only over the leaves of a given node. + +2007-10-19 Kasper Peeters + + * Released 2.4. + +2007-10-18 Kasper Peeters + + * Added max_depth() members. + + * Fixed a bug in begin_fixed() which would fail on + + A + / \ + B C + / \ + D E + / \ + F G + + when asked for the first node at depth 3 from 'A' (since it + failed to go back up the tree from 'D'). + +2007-08-21 Kasper Peeters + + * Released 2.31. + + * Added GPL version 3 licensing as an option. + +2007-01-19 Kasper Peeters + + * Fixed a bug in "replace" which appeared when trying to replace a + head node (it tried to access the parent). + +2006-11-29 Kasper Peeters + + * Release 2.3. + + Fixed a bug in number_of_siblings which only counted siblings in + one direction (thanks to Fanzhe Cui for pointing this out). + +2006-08-20 Kasper Peeters + + * Released 2.2. + + * Added operator== and operator!= for fixed_depth_iterator. + +2006-08-07 Kasper Peeters + + * Released 2.1. + + * Added leaf iterators, code contributed by Peter Wienemann. + + * Fixed a bug in is_valid (thanks to Antonio Morillas). 1.131. + +2006-07-19 Kasper Peeters + + * Fixed bugs in move_before and move_after which would show up + when the node was already in the right place. 1.130. + +2006-03-02 Kasper Peeters + + * Added the "wrap" member function. + +2006-03-01 Kasper Peeters + + * Added a simple queue-based breadth-first iterator. + +2006-01-31 Kasper Peeters + + * Fixed move_before to work when the target is a sibling_iterator + pointing to the end of a range of siblings. + +2005-11-20 Kasper Peeters + + * Added move_after, which for some mysterious reason was + missing. Thanks to Dennis Jones for pointing this out. + + * Fixed a bug in operator++ for post_order iterators + (skip_children could remain set if no next sibling present). + Thanks to Ohad for pointing out the bug. + +2005-10-12 Kasper Peeters + + * Fixed a bug in the 'sort' member which takes a Comparator + function object (thanks to Robin Taylor for the patch). + +2005-09-14 Kasper Peeters + + * Doxygen documentation added, plus a new web page. + +2004-11-05 Kasper Peeters + + * Fixed a bug which shows up when inserting nodes at the top of + the tree (thanks to Matthias Bernt for pointing me to this one). + +2004-07-21 Kasper Peeters + + * Fixed kp::destructor -> destructor. + + * Moved body of 'compare_nodes::operator()' into the class + declaration in order to satisfy buggy Borland compilers (and stop + regular email messages about this problem). + + * Fixed a completely buggy number_of_siblings() (thanks to Caleb + Epstein for the patch). + +2004-02-04 Kasper Peeters + + * Released 1.106 + + * Fixed a bug in insert(sibling_iterator, const T&) (thanks to + Maxim Yegorushkin for the patch). + +2003-11-21 Kasper Peeters + + * Put some things in a namespace to avoid clashes with other + libraries. + +2003-10-13 Kasper Peeters + + * Released 1.102. + + * Fixed return type of postincrement/decrement operators (thanks + to Yevhen Tymokhin for pointing this out). + +2003-09-18 Kasper Peeters + + * Fixes for standard compliance, as required to compile with + gcc 3.4 and later. + +2003-08-12 Kasper Peeters + + * Added 'empty' member (patch by Michael Vogt). + +2003-08-01 + + * Released 1.95 + + * Fixed two bugs in sort (which were corrupting the tree); thanks + to Michael Vogt for informing me about the problem. + +2003-07-17 + + * Added a hack to enable compilation with STLport. + +2003-07-11 + + * Released 1.90 + + * Added postfix increment and decrement operators; thanks to + Claudio Andreatta for sending the patch. + + * Fixed a bug in reparent(iter pos, iter from). Thanks to Claudio + Andreatta for fixing this. + +2003-06-25 Kasper Peeters + + * Many bug fixes for fixed depth iterators, thanks to Ruben + Niederhagen for pointing out several problems (a few still exist, + see the 'TODO' part of tree.hh). + +2003-04-17 Kasper Peeters + + * Released 1.85 + + * Corrected return type of operator++ and friends. + + * Added preliminary support for 'fixed_depth_iterator' to iterate + over children at a given level. Not quite finished yet, sorry. + +2003-03-24 Kasper Peeters + + * Released 1.83 + + * Changed return type of 'child' member function to be a sibling + iterator instead of a reference to the actual node (sorry for the + incompatibility with previous versions). Change also propagated to + tree_msvc.hh. + +2003-02-07 + + * Released 1.80 + + * Fixed another bug in sort (thanks to Tony Cook for fixing this + bug). + +2003-01-29 Kasper Peeters + + * Released 1.78. + + * Fixed a bug in sort, which resulted in a corrupt tree (thanks to + Michael Vogt for fixing this bug). + +2003-01-07 Kasper Peeters + + * Released 1.75 and msvc version 1.72 + + * Fixed a wrongly specialised 'insert' method for + sibling_iterators (thanks to Tony Cook for pointing this out). + +2002-11-15 Kasper Peeters + + * Released 1.72 + + * Fixed a bug in 'index' when called on nodes at the top level of + the tree (thanks to David Zajic for the bug report). Be warned + that the top level is a bit special at the moment; the end + sibling_iterator is ill-defined for siblings there (to be fixed in + a future version). + +2002-10-31 Kasper Peeters + + * Released 1.70. + + * Finished the merge algorithm, updated the documentation with + examples about its use, and added a test-case to the test_tree.cc + program. + + * Fixed a bug in pre_order_iterator::operator--. + +2002-10-20 Kasper Peeters + + * Released 1.66. + +2002-10-15 Kasper Peeters + + * Code for post_order_iterator implemented. + +2002-10-13 Kasper Peeters + + * Rewrote large parts of the code to allow for multiple iterator + types, such as pre_order_iterator (which was the previous iterator + type), post_order_iterator and so on. This required small changes + to the interface, the most visible one being + + - insert(iterator, iterator) for the insertion of a subtree + is now called insert_subtree(iterator, iterator). + + Apologies if this breaks your code. + +2002-10-11 Kasper Peeters + + * Removed '(void)' type declarations in favour of the C++ standard + empty brackets '()'. + +2002-10-10 Kasper Peeters + + * Added 'index' in response to a discussion on the Boost mailing + list. + +2002-10-03 Kasper Peeters + + * reparent(iterator,sibling_iterator,sibling_iterator) now accepts + an empty range, in which case it does nothing (request by Jos de + Laender). + + * Fixed a bug in the iterator(sibling_iterator) constructor + (thanks to Jos de Laender for pointing this out). + +2002-09-04 Kasper Peeters + + * Fixed a bug in insert_after (thanks to Carl Blanchette for the + patch). + +2002-08-29 Kasper Peeters + + * The problem in test_tree of the previous item was actually do to + tree::end(iterator) returning the end of the tree, not the end of + the current sibling list. Fixed now, released 1.55. + +2002-08-26 Kasper Peeters + + * Released 1.54. + + * Printing a single-node tree in test_tree would result in a + segfault; more robust now (thanks to Yutaka Sato for the bug + report). + +2002-05-07 Kasper Peeters + + * Fixed a bug in "sort" which would remove duplicate nodes altogether. + +2002-03-24 Kasper Peeters + + * Added "append_child" without child argument, to add empty child + node. + +2002-05-04 Kasper Peeters + + * Released 1.45. + + * Removed restriction of having only a single node at the top of + the tree (associated with this, the top nodes should now be inserted + with "insert", not with "append_child"). + + * Fixes for ISO compatibility (now works with gcc-3.1). Thanks to + Olivier Verdier. + diff --git a/lib/tree-2.81/Makefile b/lib/tree-2.81/Makefile new file mode 100644 index 0000000..ee30472 --- /dev/null +++ b/lib/tree-2.81/Makefile @@ -0,0 +1,27 @@ + +RELEASE=2.8 +HTML=${HOME}/public_html/ + +.PHONY: doc tarball + +tarball: + git archive --format=tar --prefix=tree-${RELEASE}/ HEAD | gzip > ${HOME}/tmp/tree-${RELEASE}.tar.gz + +site: tarball doc + install -d ${HTML}/tree + install -d ${HTML}/tree/doxygen/html + install doc/index.html doc/tree.css doc/tree.jpg ChangeLog ${HTML}/tree + install src/test_tree.cc src/test_tree.output src/tree_example.cc src/tree.hh src/tree_util.hh ${HTML}/tree + install doxygen/html/* ${HTML}/tree/doxygen/html + install ${HOME}/tmp/tree-${RELEASE}.tar.gz ${HTML}/tree + install ${HOME}/tmp/kt_temp/kt_temp_tree/tree.pdf ${HTML}/tree + +upload: + rsync -avz ${HTML}/tree/ zmaya:tree + +doc: + (cd doc; kt -f tree.tex) + doxygen doc/doxygen_tree.config + +test_tree: test_tree.o + g++ -o test_tree test_tree.o diff --git a/lib/tree-2.81/doc/documentation.html b/lib/tree-2.81/doc/documentation.html new file mode 100644 index 0000000..59d3226 --- /dev/null +++ b/lib/tree-2.81/doc/documentation.html @@ -0,0 +1,220 @@ + + + + + + + +tree.hh: an STL-like C++ tree class, documentation + + + +
+
+
+ +Bookmark and Share + +
+
+ [background image] +
+
+

tree.hh: an STL-like C++ tree class

+

+ Kasper Peeters, kasper.peeters (at) phi-sci.com +

+
+
+ + + + + +
+ + + +

Data structure overview

+ +
The data structure of the tree class is depicted + below (see the documentation for more detailed information). + Each node contains a pointer to the first and last child element, + and each child contains pointers to its previous and next sibling: + [structure
+		  diagram] +
+ +
+ Iterators come in various types. The normal iterator iterates depth-first + over all nodes. The beginning and end of the tree can be obtained by using the + begin() and end() members. The other type of iterator + only iterates over the nodes at one given depth (ie. over all siblings). One + typically uses these iterators to iterate over all children of a node, in which + case the [begin,end) range can be obtained by calling begin(iterator) + and end(iterator).
+ +
Iterators can be converted from one type to the other; this includes the `end' + iterators (all intervals are as usual closed at the beginning and open + at the end).
+ +

Sample program

+ +
+ Here is a small sample program to illustrate + how tree.hh is used in practise. + +
+
#include <algorithm>
+#include <string>
+#include <iostream>
+#include "tree.hh"
+
+using namespace std;
+
+int main(int, char **)
+   {
+   tree<string> tr;
+   tree<string>::iterator top, one, two, loc, banana;
+   
+   top=tr.begin();
+   one=tr.insert(top, "one");
+   two=tr.append_child(one, "two");
+   tr.append_child(two, "apple");
+   banana=tr.append_child(two, "banana");
+   tr.append_child(banana,"cherry");
+   tr.append_child(two, "peach");
+   tr.append_child(one,"three");
+   
+   loc=find(tr.begin(), tr.end(), "two");
+   if(loc!=tr.end()) {
+   tree<string>::sibling_iterator sib=tr.begin(loc);
+   while(sib!=tr.end(loc)) {
+     cout << (*sib) << endl;
+     ++sib;
+     }
+   cout << endl;
+   tree<string>::iterator sib2=tr.begin(loc);
+   tree<string>::iterator end2=tr.end(loc);
+   while(sib2!=end2) {
+     for(int i=0; i<tr.depth(sib2)-2; ++i) 
+        cout << " ";
+     cout << (*sib2) << endl;
+     ++sib2;
+     }
+   }
+}
+
+ The output of this program is +
+
apple
+banana
+peach
+
+apple
+banana
+ cherry
+peach
+
+ Note that this example only has one element at the + top of the tree (in this case that is the node containing "one") but + it is possible to have an arbitary number of such elements (then the + tree is more like a "bush"). Observe the way in which the two types of + iterators work. The first block of output, obtained using the + sibling_iterator, only displays the children directly below "two". The + second block iterates over all children at any depth below "two". In + the second output block, the depth member has been used + to determine the distance of a given node to the root of the + tree. +
+ +

API documentation

+ +
+ Documentation is available in the form of + a pdf file. This file is also available + in the tarball as a LaTeX file. Further information can be + obtained by reading the test program (included in the + distribution). Also look at the simple + example below. +
+ +
+ The most complete documentation of the interface is always + available in the doxygen + generated documentation. +
+
+ +
+ +

+ + Valid XHTML 1.0 Strict +

+ + + + + + + + +
+ + + diff --git a/lib/tree-2.81/doc/download.html b/lib/tree-2.81/doc/download.html new file mode 100644 index 0000000..4bb45a7 --- /dev/null +++ b/lib/tree-2.81/doc/download.html @@ -0,0 +1,175 @@ + + + + + + + +tree.hh: an STL-like C++ tree class, download + + + +
+
+
+ +Bookmark and Share + +
+
+ [background image] +
+
+

tree.hh: an STL-like C++ tree class

+

+ Kasper Peeters, kasper.peeters (at) phi-sci.com +

+
+
+ + + + + +
+ + + +

Download

+ +
Everything (the header file, examples, documentation + and all other things referred to on this page) is contained in the + tarball
+ +
+ Feel free to copy the header tree.hh + (which is all you need code-wise) into your own source + directory as long as you respect the license (see above). +
+ +
+ The list of changes can be found in the ChangeLog. +
+ +
+ There is a small utility + library tree_util.hh originally + written by Linda Buisman. This library contains a number of + functions to output a tree as text, to aid in debugging your + project. +
+ +
The current version works with GNU gcc 3.x and + higher, Borland C++ builder and Microsoft Visual C++ 7.1 and + higher (I no longer support older versions of Visual C++). It is + compatible with STLport (though older versions may not work + correctly, best to upgrade to something fairly recent). +
+ +
The library is available for free, but if it + helps you a lot, why not consider a small donation? + + Your contribution is greatly appreciated! +
+ + +

Installation

+ +
+ No installation is required as the tree.hh library is + contained in the single header file tree.hh. Just copy it into + your source directory (and upgrade it from the master site + when a new version becomes available). +
+ +
+ +
+ +

+ + Valid XHTML 1.0 Strict +

+ + + + + + + + +
+ + + diff --git a/lib/tree-2.81/doc/doxygen_tree.config b/lib/tree-2.81/doc/doxygen_tree.config new file mode 100644 index 0000000..5095e07 --- /dev/null +++ b/lib/tree-2.81/doc/doxygen_tree.config @@ -0,0 +1,270 @@ +# Doxyfile 1.4.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = tree +PROJECT_NUMBER = "release 2.0" +OUTPUT_DIRECTORY = doxygen +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src/tree.hh +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/lib/tree-2.81/doc/favicon.ico b/lib/tree-2.81/doc/favicon.ico new file mode 100644 index 0000000..4eb6ffe Binary files /dev/null and b/lib/tree-2.81/doc/favicon.ico differ diff --git a/lib/tree-2.81/doc/favicon.png b/lib/tree-2.81/doc/favicon.png new file mode 100644 index 0000000..69d16b3 Binary files /dev/null and b/lib/tree-2.81/doc/favicon.png differ diff --git a/lib/tree-2.81/doc/filler.png b/lib/tree-2.81/doc/filler.png new file mode 100644 index 0000000..548e1e4 Binary files /dev/null and b/lib/tree-2.81/doc/filler.png differ diff --git a/lib/tree-2.81/doc/index.html b/lib/tree-2.81/doc/index.html new file mode 100644 index 0000000..f807fa2 --- /dev/null +++ b/lib/tree-2.81/doc/index.html @@ -0,0 +1,205 @@ + + + + + + + +tree.hh: an STL-like C++ tree class + + + +
+
+
+ +Bookmark and Share + +
+
+ + + + + +
+
+ [background image] +
+
+

tree.hh: an STL-like C++ tree class

+

+ Kasper Peeters, kasper.peeters (at) phi-sci.com +

+
+
+ + + + + +
+ + + +

Overview

+ +
+ The tree.hh library for C++ provides an STL-like container class + for n-ary trees, templated over the data stored at the nodes. Various + types of iterators are provided (post-order, pre-order, and + others). Where possible the access methods are compatible with the STL + or alternative algorithms are available. The library is available + under the terms of the GNU General Public License version 2 or + 3 (see below).
+ +
Documentation is available in the form of + a pdf file. See + the documentation page for + more details and sample programs. +
+ +
The tree.hh library is meant for generic n-ary + trees. For binary trees, AVL trees, quad trees and other data + structures, you may want to look elsewhere.
+ +
The library is available for free, but if it + helps you a lot, why not consider a small donation? + + Your contribution is greatly appreciated! +
+ +
+ I have considered this class for inclusion in Boost. However, + there are many ways to implement a tree container, and there + is no good way to simultaneously satisfy everyone who would + use it. See the discussion on the Boost mailing list in + 2002 + and 2009. +
+ +

License

+ +
In principle, the tree.hh code is + available under the terms of the GNU General Public + License 2 + or 3. However, + if you would like to use tree.hh under different + conditions, contact me and we will work something out.
+ +
+ This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program. If not, + see http://www.gnu.org/licenses/. +
+ +
If you use tree.hh, + please satisfy my curiosity and write me a small email with + a bit of explanation of your software and the role of my tree + class in it.
+ +
+ +
+ +

+ + Valid XHTML 1.0 Strict +

+ + + + + + + + +
+ + + diff --git a/lib/tree-2.81/doc/projects.html b/lib/tree-2.81/doc/projects.html new file mode 100644 index 0000000..03af4d5 --- /dev/null +++ b/lib/tree-2.81/doc/projects.html @@ -0,0 +1,162 @@ + + + + + + + +tree.hh: an STL-like C++ tree class, projects using tree.hh + + + +
+
+
+ +Bookmark and Share + +
+
+ [background image] +
+
+

tree.hh: an STL-like C++ tree class

+

+ Kasper Peeters, kasper.peeters (at) phi-sci.com +

+
+
+ + + + + +
+ + + +

Projects using tree.hh

+ +
The tree.hh library is used in various projects: +
+
Cadabra
+
A field-theory motivated approach to symbolic computer + algebra.
+
Gnash
+
Gnash is a GNU Flash movie player. Previously, it was only + possible to play flash movies with proprietary software. While there + are some other free flash players, none support anything beyond SWF + v4. Gnash is based on GameSWF, and supports many SWF v7 features.
+
htmlcxx
+
A simple non-validating css1 and html parser for C++.
+
Principles of Compiler Design
+
A course in compiler design at the Simon Fraser University, Canada.
+
liborigin
+
A library for reading OriginLab OPJ project files, which is used + by QtiPlot + and LabPlot, two + applications for data analysis and visualisation.
+
EChem++
+
A project realizing the idea of a Problem Solving Environment + (PSE) in the field of computational electrochemistry. Computer + controlled experimental measurements, numerical simulation and + analysis of electrochemical processes will be combined under a common + user interface.
+
LZCS
+
A semistructured document transformation tool. LZCS compresses + structured documents taking advantage of the redundant information + that can appear in the structure. The main idea is that frequently + repeated subtrees may exist and these can be replaced by a backward + reference to their first occurance. See the accompanying + paper for more details.
+
libOFX
+
A parser and an API designed to allow applications to very easily support OFX + command responses, usually provided by financial institutions for + statement downloads.
+
A genetic programming project
+
See this paper for + more information.
+
FreeLing
+
The FreeLing package consists of a library providing language analysis services (such as morfological analysis, date recognition, PoS tagging, etc.)
+
+ Let me know about your project when you are using + tree.hh, so that I can add it to the list.
+
+ +
+ +

+ + Valid XHTML 1.0 Strict +

+ + + + + + + + +
+ + + diff --git a/lib/tree-2.81/doc/structure.png b/lib/tree-2.81/doc/structure.png new file mode 100644 index 0000000..fbad024 Binary files /dev/null and b/lib/tree-2.81/doc/structure.png differ diff --git a/lib/tree-2.81/doc/structure.svg b/lib/tree-2.81/doc/structure.svg new file mode 100644 index 0000000..8a2bf21 --- /dev/null +++ b/lib/tree-2.81/doc/structure.svg @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + head 1 + + + + head 2 + + + + + node + + + + node + + + + node + + + next sibling + previous sibling + + + first child + + + + last child + + + + + + + head n + + + + + node + + + + node + + + + node + + + + + + + + depth + + + diff --git a/lib/tree-2.81/doc/tree.css b/lib/tree-2.81/doc/tree.css new file mode 100644 index 0000000..03b84c8 --- /dev/null +++ b/lib/tree-2.81/doc/tree.css @@ -0,0 +1,171 @@ + +body { + font: 10pt "Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, sans-serif; +} +div#container { + min-width: 700px; + margin-left: 20px; + margin-right: 20px; + margin-top: 20px; + margin-bottom: 30px; + background: #f0f0f0; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -moz-box-shadow: 1px 1px 9px #888; + padding: 5px 15px 5px 15px; +} +div#titletxt { + margin: -150px 0 30px 240px; + height: 70px; +} +div#filler { + width: 100%; + height: 160px; + background: url("filler.png"); + padding: 0; + margin: 0; + margin-top: 5px; + -moz-box-shadow: 1px 1px 5px #888; +} +img#treeimg { + margin-top: 0; +} + +/* Donations */ + +form#donate { + text-align: center; + margin-top: 1ex; + margin-bottom: 1ex; +} + +/* Layout containers */ + +div#linkbar { + margin-right: 135px; + display: inline; +} +div#main { + margin-right: 135px; + display: inline; +} +div#sidebar { + margin-top: 16px; + float: right; + display: inline; + width: 125px; + margin-left: 10px; +} +div#flush { + clear: both; +} + + +/* Title color/style */ + +#title h1 { + font-size: 30px; + color: #b00000; +} +#title h2 { + font-size: 11pt; + font-weight: normal; + color: black; + border-bottom: 0px; +} + +/* Menu */ + +ul#menubar { + margin-top: 0px; + margin-bottom: 35px; + margin-right: 2ex; + text-align: right; +} + +#menubar li { + display: inline; + background: #b00000; + color: white; + font-weight: bold; + padding: .5ex 1ex .5ex 1ex; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -moz-box-shadow: 1px 1px 9px #888; +} +#menubar li:hover { + background: #009000; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -moz-box-shadow: 1px 1px 6px #888; +} + +#menubar a { + text-decoration: none; + color: white; +} + +/* Main color/style */ + +div#share { + position: absolute; + right: 50px; + top: 36px; +} +div#plusone { + position: absolute; + left: 50px; + top: 36px; +} + +#main h2 { + margin-top: 2ex; + margin-right: 135px; + display: block; + background: #b00000; + color: white; + padding-left: 1ex; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -moz-box-shadow: 1px 1px 9px #888; +} +div.text { + margin-left: 120px; + margin-bottom: 2ex; + margin-right: 145px; +} +div.license { + margin-left: 140px; + margin-bottom: 2ex; + margin-right: 155px; +} +div.filename { + margin-left: 200px; + margin-bottom: 1ex; +} +img.structure { + margin-top: 1ex; + margin-bottom: 1ex; + margin-left: 3ex; +} +dd { + margin-bottom: 2ex; +} + +img { + border-style: none; +} + +/* Code listing */ + +div.code { + margin: 1ex; + width: 90%; + border: dotted 1px black; + background: #f8f8f8; + font-size: 8pt; + padding: 1ex; +} +.code pre { + white-space: pre-wrap; +} diff --git a/lib/tree-2.81/doc/tree.jpg b/lib/tree-2.81/doc/tree.jpg new file mode 100644 index 0000000..d6f58f7 Binary files /dev/null and b/lib/tree-2.81/doc/tree.jpg differ diff --git a/lib/tree-2.81/doc/tree.png b/lib/tree-2.81/doc/tree.png new file mode 100644 index 0000000..04fa420 Binary files /dev/null and b/lib/tree-2.81/doc/tree.png differ diff --git a/lib/tree-2.81/doc/tree.tex b/lib/tree-2.81/doc/tree.tex new file mode 100644 index 0000000..4ba233d --- /dev/null +++ b/lib/tree-2.81/doc/tree.tex @@ -0,0 +1,388 @@ +\documentclass[11pt]{kasper} +% +% If you do not have 'kasper.cls', see +% http://www.damtp.cam.ac.uk/user/kp229/texstuff . + +\usepackage{makeidx} +\usepackage{verbatim} +\usepackage{relsize} +\makeindex +%\newcommand{\toindex}[1]{#1\index{#1}} + +\newcommand{\member}[1]{{\tt #1}\index{#1}} +%\newcommand{\member}[1]{{\tt #1}} + +\def\mystrut{\vbox to 8.5pt{}\vtop to 3.5pt{}} +\def\V{\hskip10pt\vrule\hskip10pt} +\def\T{\hskip10pt\vrule\vrule height2.5pt depth -2.1pt width 10pt} +\def\L{\hskip10pt\vrule height 8.5pt depth -2.1pt + \vrule height2.5pt depth -2.1pt width 10pt} +\def\N{\hskip10pt\phantom{\vrule}\hskip10pt} +\def\hw{\hskip-1000pt plus 1fil} + +% to test: insert before end of subtree + +\begin{document} +\title{{\tt tree.hh} documentation} +\author{Kasper Peeters} +\email{kasper.peeters@gmail.com} +\maketitle +\begin{abstract} +The {\tt tree.hh} library for C++ provides an STL-like container class +for n-ary trees, templated over the data stored at the nodes. Various +types of iterators are provided (post-order, pre-order, and +others). Where possible the access methods are compatible with the STL +or alternative algorithms are available. The library is available +under the terms of the GNU General Public License.\\[3ex] +Code and examples available at: {\tt http://tree.phi-sci.com/}\\[3ex] +{\bf This documentation is not yet entirely complete. Refer to the {\tt +tree.hh} header file for a full list of member functions.} +\end{abstract} +\vfill +\maketoc +\eject + +\begin{sectionunit} +\title{Overview} +\maketitle +\begin{sectionunit} +\title{The container class} +\maketitle +The tree class of {\tt tree.hh} is a templated container class in the +spirit of the STL. It organises data in the form of a so-called n-ary +tree. This is a tree in which every node is connected to an arbitrary +number of child nodes. Nodes at the same level of the tree are called +``siblings'', while nodes that are below a given node are called its +``children''. At the top of the tree, there is a set of nodes which +are characterised by the fact that they do not have any parents. The +collection of these nodes is called the ``head'' of the tree. See +figure~\ref{f:overview} for a pictorial illustration of this +structure (90 degrees rotated for convenience). +\begin{figure}[th] +\begin{center} +\includegraphics[width=.5\textwidth]{treefig} +\caption{Overview of the tree structure. The elements at the top of +the tree (here displayed at the left for convenience) are in the +``head'' (there can be more than one such element). Every node is +linked to its children using the ``first child'' and ``last child'' +links. In addition, all nodes on a given level are doubly-linked using +the ``previous sibling'' and ``next sibling'' links. The ``depth'' of +a given node refers to the horizontal distance from the head nodes.} +\label{f:overview} +\end{center} +\end{figure} + +The tree class is templated over the data objects stored at the nodes; +just like you can have a {\tt vector} you can now have a +{\tt tree}. Many STL algorithms work on this data structure, +and where necessary alternatives have been provided. +\medskip + +\end{sectionunit} +\begin{sectionunit} +\title{Iterators} +\maketitle + +The essential difference between a container with the structure of a +tree and the STL containers is that the latter are ``linear''. While +the STL containers thus only have essentially one way in which one can +iterate over their elements, this is not true for trees. The {\tt +tree.hh} library provides (at present) four different iteration +schemes. To describe them, consider the following tree: +\begin{equation*} +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + root \hw\cr + \T A \cr + \V \T B \cr + \V \L C \cr + \L D \cr + \N \T E \cr + \N \L F \cr}} +\end{equation*} +The three iteration types and the resulting order in which nodes are +visited are tabulated below: +\begin{center} +\begin{tabular}{llll} +pre-order (default) & ``element before children'' & +\member{pre\_order\_iterator} & root A B C D E F \\ +post-order & ``element after children'' & +\member{post\_order\_iterator} & B C A E F D root \\ +breadth-first & & +\member{breadth\_first\_iterator} & root A D B C E F \\ +sibling & ``only siblings'' & +\member{sibling\_iterator} & (for ex.) A D \\ +fixed-depth & & +\member{fixed\_depth\_iterator} & (for ex.) A D \\ +leaf & & +\member{leaf\_iterator} & B C E F +\end{tabular} +\end{center} +The pre-order ones are the default iterators, and therefore also known +under the name of {\tt iterator}. Sibling iterators and fixed-depth +iterators iterate only over the nodes at a given depth of the +tree. The former restrict themselves to the child nodes of one given +node, while the latter iterates over all child nodes at the given +depth. Finally, leaf iterators iterate over all leafs (bottom-most) +nodes of the tree. + +There are copy constructors that will convert iterators of the +various types into each other. The post- and pre-order iterators are +both also known as ``depth-first'', in contrast to the +``breadth-first'' iterator. + +The begin and end iterators of a tree can be obtained using +\member{begin()} and \member{end()} (for pre-order iterators) or +alternatively \member{begin\_post()} and \member{end\_post()} (for +post-order iterators) and \member{begin\_leaf()} and +\member{end\_leaf()} (for leaf iterators). Similarly, the begin and +end sibling iterators can be obtained by calling +\member{begin(iterator)} and \member{end(iterator)}. The range of +children of a given node can also be obtained directly from an +iterator, by using the {\tt iterator::begin()} and {\tt +iterator::end()} member functions. + +If you want to (temporarily) make an iterator not go into the child +subtree, call the member function \member{skip\_children}. This will only +keep effect for a single increment or decrement of the +iterator. Finally, whether or not an iterator is actually pointing at +a node (i.e.~is not an ``end'' iterator) can be tested using the +\member{is\_valid(iterator)} member of the tree class. + +\end{sectionunit} +\end{sectionunit} + +\begin{sectionunit} +\title{Basic operations} +\maketitle +\begin{description} +\item[Initialising] There are two nontrivial constructors. One which takes +a single node element as argument. It constructs a tree with this node +begin the sole node in the head (in other words, it is a combination +of a trivial constructor together with a \member{set\_head} call). +The other non-trivial constructor takes an iterator, and copies the +subtree starting at that node into the newly created tree (useful for +constructing new tree objects given by subtrees of existing trees). + +\item[Tree traversal] Besides the \member{operator++} and +\member{operator--} members for step-wise traversal through the tree, +it is also possible to use the \member{operator+=} and \member{operator-=} +member functions to make more than one step at the same time (though +these are linear time, not amortized constant). The result of stepping +beyond the end of the tree or stepping beyond the end of a sibling +range (for sibling iterators) is undefined. + +The parent of a given node can be reached by calling the \member{parent} +member of the tree object, giving it an iterator pointing to the node. + +If you know the number of children of a given node, you can get direct +access to the $n$th child by using the \member{child} member +function. Note that the value of the index is not checked and should +therefore always be valid. + +\item[Appending child nodes] Nodes can be added as children of a given +node using the \member{append\_child} member function. + +\item[Inserting nodes] Nodes can be inserted at the same depth as a +given other node using the \member{insert} and \member{insert\_after} +members functions. This is also how you insert the first node into a +tree. +\end{description} +\end{sectionunit} + +\begin{sectionunit} +\title{Other algorithms} +\maketitle +\begin{sectionunit} +\title{Non-mutating algorithms} +\maketitle +\begin{description} +\item[Counting nodes] The total number of nodes of a tree can be +obtained using the \member{size} member function, while the number of +children of a given node can be obtained with a call to +\member{number\_of\_children(iterator)}. Similarly, the number of +nodes at a given depth (the number of siblings of a given node) can be +obtained using the \member{number\_of\_siblings} member function. +\item[Determining depth] The \member{depth()} member function returns the +distance of a node to the root. +\item[Accessing siblings by their index] See the next item. +\item[Determining index in a sibling range] In order to determine the +index of a node in the range of siblings to which it belongs, use the +\member{index(sibling\_iterator)} member function. The first sibling node +has index 0. The reverse of this function (obtaining a sibling node +given its index in the range of siblings) is called +\member{child(const iterator\_base\&, unsigned int)}. +\item[Comparing trees] While the STL \member{equal} algorithm can be used +to compare the values of the nodes in two different trees, it does not +know about the structure of the tree. If you want the comparison to +take this into account, use the \member{equal(iterator, iterator, +iterator, BinaryPredicate)} call of the tree class. As an addition to +the STL algorithm, the length of the first range does not have to be +equal to the length of the range pointed to by the second iterator. + +There is also an \member{equal\_subtree} algorithm which takes only +two iterators, pointing to the (single-node) heads of two +subtrees. +\end{description} +\end{sectionunit} + +\begin{sectionunit} +\title{Mutating algorithms} +\maketitle +\begin{description} +\item[Erasing nodes and subtrees] In order to remove a node including +its children from the tree, use the \member{erase(iterator)} call. If you +just want to erase the children, but not the node itself, use the +\member{erase\_children(iterator)} call. + +\item[Replacing individual nodes or subtrees] + +\item[Flattening subtrees] The procedure of moving all children of a +given node to be siblings of that node is called ``flattening''; it +acts as +\begin{equation*} +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \T banana\cr + \V \T pear \cr + \V \T strawberry \cr + \V \L cherry \cr + \L grape\cr}}\quad\rightarrow\quad +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \T banana\cr + \T pear \cr + \T strawberry \cr + \T cherry \cr + \L grape\cr}} +\end{equation*} +% \begin{screen} +% apple apple +% banana banana +% pear -> pear +% strawberry strawberry +% cherry cherry +% grape grape +% \end{screen} +when the tree is flattened at the ``banana'' node. + +\item[Moving or exchanging subtrees] Simple exchange of one sibling node with the +next one is done through the member function \member{swap(sibling\_iterator)}. The +iterator remains valid and remains pointing to the moved subtree. + +More complicated move operations are the \member{move\_ontop}, +\member{move\_before} and \member{move\_after} ones. These all take +two iterators, a source and a target. The member +\member{move\_ontop(target, source)} removes the `target' node and +all its children, and replaces it with the `source' node and its +children. The `source' subtree is removed from its original location. +The other two move members do a similar thing, differing only in the +node which is to be replaced. + +\item[Extracting subtrees] You can create a new tree object +filled with the data of a subtree of the original tree. This is +analogous to the extraction of a substring of a string. The relevant +member function is \member{subtree(sibling\_iterator, +sibling\_iterator)} which takes a range of siblings as argument. +There is also a slight variation of this member, which does not return +a tree object but instead populates one that is passed as an argument +(useful if you want to call this on a tree object subclassed from +{\tt tree}. + +\item[Sorting] The standard STL sort algorithm is not very useful for +trees, because it only exchanges values, not nodes. Applying it to a +tree would mean that the structure of the tree remains unmodified, +only node values get moved around (not their subtrees). + +Therefore, the {\tt tree} class has its own sort member. It comes in +two forms, just like the STL sort, namely +\begin{screen} +void sort(sibling_iterator from, sibling_iterator to, bool deep=false); + +template +void sort(sibling_iterator from, sibling_iterator to, + StrictWeakOrdering comp, bool deep=false); +\end{screen} +The result of a call to either of these is that the nodes in the range +described by the two iterators get sorted. If the boolean {\tt deep} +is true, the subtrees of all these nodes will get sorted as well (and +so one can sort the entire tree in one call). As in the STL, you can +use the second form of this function to pass your own comparison +class. + +If the nodes to which the two iterators point are not in the same +sibling range (i.e.~not at the same depth in the tree), the result is undefined. + +\item[Merging] One way in which one might think of indicating the +position where new nodes are to be inserted, is to give the path that +leads to the insertion point. For instance, given the tree +\begin{equation*} +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \T banana\cr + \V \T pear \cr + \V \T strawberry \cr + \V \L cherry \cr + \L grape\cr}} +\end{equation*} +one could imagine using the sub-tree +\begin{equation*} +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \L banana\cr + \N \T coconut \cr + \N \L raspberry \cr}} +\end{equation*} +to indicate that the nodes ``coconut'' and ``raspberry'' are to be +inserted as new children of the ``banana'' node. In {\tt tree.hh} this +process is called \emph{tree merging}. It can do the simple addition +of children as above, but actually handles the generic case too: as +an example consider the merge +\begin{equation*} +\text{\tt merge}\left[ +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \T banana\cr + \V \T pear \cr + \V \T strawberry \cr + \V \L cherry \cr + \T grape\cr + blueberry \cr}}\quad, \quad +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \T banana\cr + \V \T coconut \cr + \V \L raspberry \cr + \T tangerine \cr + \V \L plum\cr + blueberry \cr + \N \L orange \cr}}\right]\quad\rightarrow\quad +\vcenter{\offinterlineskip +\halign{&#\mystrut\hfil\cr + apple \hw\cr + \T banana\cr + \V \T pear\cr + \V \T strawberry\cr + \V \T cherry\cr + \V \T coconut \cr + \V \L raspberry \cr + \T grape\cr + \T tangerine \cr + \V \L plum\cr + blueberry \cr + \N \L orange \cr}} +\end{equation*} +As is clear from the above, the arguments to \member{merge} are two +sibling ranges. +\end{description} +\end{sectionunit} +\end{sectionunit} + +\printindex +\end{document} diff --git a/lib/tree-2.81/doc/tree2.png b/lib/tree-2.81/doc/tree2.png new file mode 100644 index 0000000..9dd31b0 Binary files /dev/null and b/lib/tree-2.81/doc/tree2.png differ diff --git a/lib/tree-2.81/doc/treefig.eps b/lib/tree-2.81/doc/treefig.eps new file mode 100644 index 0000000..c813732 --- /dev/null +++ b/lib/tree-2.81/doc/treefig.eps @@ -0,0 +1,190 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: tree.eps +%%Creator: fig2dev Version 3.2 Patchlevel 0-beta3 +%%CreationDate: Fri May 3 12:41:08 2002 +%%For: kp229@church.amtp.cam.ac.uk (Kasper Peeters) +%%Orientation: Portrait +%%BoundingBox: 0 0 324 252 +%%Pages: 0 +%%BeginSetup +%%EndSetup +%%Magnification: 1.0000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-126.0 342.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n -1000 6700 m -1000 -1000 l 8494 -1000 l 8494 6700 l cp clip + 0.06000 0.06000 sc +% Polyline +7.500 slw +gs clippath +4380 3828 m 4350 3948 l 4320 3828 l 4320 3990 l 4380 3990 l cp +4320 3222 m 4350 3102 l 4380 3222 l 4380 3060 l 4320 3060 l cp +clip +n 4350 3075 m 4350 3975 l gs col0 s gr gr + +% arrowhead +n 4320 3222 m 4350 3102 l 4380 3222 l 4350 3222 l 4320 3222 l cp gs 0.00 setgray ef gr col0 s +% arrowhead +n 4380 3828 m 4350 3948 l 4320 3828 l 4350 3828 l 4380 3828 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +n 4350 4350 m 4350 5475 l gs col0 s gr [] 0 sd +% Polyline +gs clippath +4021 5328 m 4039 5450 l 3966 5351 l 4028 5500 l 4083 5477 l cp +clip +n 2550 1875 m 4050 5475 l gs col0 s gr gr + +% arrowhead +n 4021 5328 m 4039 5450 l 3966 5351 l 3993 5339 l 4021 5328 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +4380 2628 m 4350 2748 l 4320 2628 l 4320 2790 l 4380 2790 l cp +4320 2022 m 4350 1902 l 4380 2022 l 4380 1860 l 4320 1860 l cp +clip +n 4350 1875 m 4350 2775 l gs col0 s gr gr + +% arrowhead +n 4320 2022 m 4350 1902 l 4380 2022 l 4350 2022 l 4320 2022 l cp gs 0.00 setgray ef gr col0 s +% arrowhead +n 4380 2628 m 4350 2748 l 4320 2628 l 4350 2628 l 4380 2628 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +3903 1695 m 4023 1725 l 3903 1755 l 4065 1755 l 4065 1695 l cp +clip +n 2550 1725 m 4050 1725 l gs col0 s gr gr + +% arrowhead +n 3903 1695 m 4023 1725 l 3903 1755 l 3903 1725 l 3903 1695 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6828 1695 m 6948 1725 l 6828 1755 l 6990 1755 l 6990 1695 l cp +clip +n 4725 1725 m 6975 1725 l gs col0 s gr gr + +% arrowhead +n 6828 1695 m 6948 1725 l 6828 1755 l 6828 1725 l 6828 1695 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +n 7275 1950 m 7275 2625 l gs col0 s gr [] 0 sd +/Times-Roman ff 180.00 scf sf +2100 1800 m +gs 1 -1 sc (head) col0 sh gr +/Times-Roman ff 180.00 scf sf +4200 1800 m +gs 1 -1 sc (node) col0 sh gr +/Times-Roman ff 180.00 scf sf +4200 3000 m +gs 1 -1 sc (node) col0 sh gr +/Times-Roman ff 180.00 scf sf +4200 4200 m +gs 1 -1 sc (node) col0 sh gr +/Times-Roman ff 180.00 scf sf +4200 5700 m +gs 1 -1 sc (node) col0 sh gr +/Times-Roman ff 180.00 scf sf +4575 2250 m +gs 1 -1 sc (next sibling) col0 sh gr +/Times-Roman ff 180.00 scf sf +4575 2475 m +gs 1 -1 sc (prev sibling) col0 sh gr +/Times-Roman ff 180.00 scf sf +4575 3450 m +gs 1 -1 sc (next sibling) col0 sh gr +/Times-Roman ff 180.00 scf sf +4575 3675 m +gs 1 -1 sc (prev sibling) col0 sh gr +/Times-Roman ff 180.00 scf sf +5850 1650 m +gs 1 -1 sc (first child) col0 sh gr +/Times-Roman ff 180.00 scf sf +2925 1650 m +gs 1 -1 sc (first child) col0 sh gr +/Times-Roman ff 180.00 scf sf +7125 1800 m +gs 1 -1 sc (node) col0 sh gr +/Times-Roman ff 180.00 scf sf +7125 2925 m +gs 1 -1 sc (node) col0 sh gr +/Times-Roman ff 180.00 scf sf +2550 3900 m +gs 1 -1 sc (last child) col0 sh gr +$F2psEnd +rs diff --git a/lib/tree-2.81/doc/treefig.fig b/lib/tree-2.81/doc/treefig.fig new file mode 100644 index 0000000..f506563 --- /dev/null +++ b/lib/tree-2.81/doc/treefig.fig @@ -0,0 +1,44 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 1 2 + 1 1 1.00 60.00 120.00 + 1 1 1.00 60.00 120.00 + 4350 3075 4350 3975 +2 1 1 1 0 7 0 0 -1 4.000 0 0 -1 0 0 2 + 4350 4350 4350 5475 +2 1 0 1 0 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2550 1875 4050 5475 +2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 1 2 + 1 1 1.00 60.00 120.00 + 1 1 1.00 60.00 120.00 + 4350 1875 4350 2775 +2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2550 1725 4050 1725 +2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4725 1725 6975 1725 +2 1 1 1 0 7 0 0 -1 4.000 0 0 -1 0 0 2 + 7275 1950 7275 2625 +4 0 0 0 0 0 12 0.0000 0 135 360 2100 1800 head\001 +4 0 0 0 0 0 12 0.0000 4 135 360 4200 1800 node\001 +4 0 0 0 0 0 12 0.0000 4 135 360 4200 3000 node\001 +4 0 0 0 0 0 12 0.0000 4 135 360 4200 4200 node\001 +4 0 0 0 0 0 12 0.0000 4 135 360 4200 5700 node\001 +4 0 0 0 0 0 12 0.0000 4 180 870 4575 2250 next sibling\001 +4 0 0 0 0 0 12 0.0000 4 180 870 4575 2475 prev sibling\001 +4 0 0 0 0 0 12 0.0000 4 180 870 4575 3450 next sibling\001 +4 0 0 0 0 0 12 0.0000 4 180 870 4575 3675 prev sibling\001 +4 0 0 0 0 0 12 0.0000 4 135 720 5850 1650 first child\001 +4 0 0 0 0 0 12 0.0000 4 135 720 2925 1650 first child\001 +4 0 0 0 0 0 12 0.0000 4 135 360 7125 1800 node\001 +4 0 0 0 0 0 12 0.0000 4 135 360 7125 2925 node\001 +4 0 0 0 0 0 12 0.0000 4 135 690 2550 3900 last child\001 diff --git a/lib/tree-2.81/doc/treefig.pdf b/lib/tree-2.81/doc/treefig.pdf new file mode 100644 index 0000000..547b9e4 --- /dev/null +++ b/lib/tree-2.81/doc/treefig.pdf @@ -0,0 +1,71 @@ +%PDF-1.3 +%Çì¢ +6 0 obj +<> +stream +xœ­UKÓ0¾ûWøÖ©YÏø}]‰—…H‡¥MPZØí +øùŒ_‰³©©h¤zÆóøÆó°E\„/¯›{b·<±{"?±°{ Ô(øÀ$ª9ˆŽ4Ž l´AjÁAh n Nb‘N ‰t°Jt—%Ê™Æ>´vÄÍ$+œvjô—èŽðž©Fó_ŃÕSDR“ÖÇx² ·qÒØþíqƒŽ‚X’²I3‚_k`?siø*Û6:£*=46†c‰Œl%!HÀ™ðM¬èpzÀ$s>0Ræ„Ô•CKPècáÀ΋u[*5! ˜Æ¤&˺ÿËc·4±@NÕ¥´¶.e’ΪipQT]ˆh«.̲ÂI1N¦Ï NÉŠHŸœ 'Í׃s…ƒip.KÙ¤Y ÎrÓÅUB(!c7éÐå(]Èb‘IccûX?§ƒÍÙæy ²«ª —VšuA®t°43褙pÐ 7áYÂA/Õœ>—™x¿çÔ Gýwj VšUj®uðê¶•tES#ë¥HSw¥HŸèöޝo^6~×Ò+ìiƒÜµ{–gàkÑú¡R@˜Š·vÓí¶oÚo è¼Ý²›ã÷í.ìXäíûÌ®ÆÕ‹z‘ΈÂ&ÃÝï~ê¿ýñ1º”$ Ê?žw?GÁŠÑ —ög«ê[Cû€¤³ïŸO/|ÓõC |M× IÄ95_ûÙ©Œ-àék´¡Në)µ‡w-¿§^øöÌÐcendstream +endobj +7 0 obj +588 +endobj +10 0 obj +<> +endobj +11 0 obj +<> +endobj +5 0 obj +<> +/Contents 6 0 R +>> +endobj +3 0 obj +<< /Type /Pages /Kids [ +5 0 R +] /Count 1 +>> +endobj +1 0 obj +<> +endobj +4 0 obj +<> +endobj +9 0 obj +<> +endobj +8 0 obj +<> +endobj +2 0 obj +<>endobj +xref +0 12 +0000000000 65535 f +0000000971 00000 n +0000001222 00000 n +0000000912 00000 n +0000001019 00000 n +0000000752 00000 n +0000000015 00000 n +0000000673 00000 n +0000001161 00000 n +0000001088 00000 n +0000000692 00000 n +0000000722 00000 n +trailer +<< /Size 12 /Root 1 0 R /Info 2 0 R +>> +startxref +1274 +%%EOF diff --git a/lib/tree-2.81/src/.gitignore b/lib/tree-2.81/src/.gitignore new file mode 100644 index 0000000..f0ef4c3 --- /dev/null +++ b/lib/tree-2.81/src/.gitignore @@ -0,0 +1,3 @@ +*.o +*.res +test1 diff --git a/lib/tree-2.81/src/Makefile b/lib/tree-2.81/src/Makefile new file mode 100644 index 0000000..7d1aba7 --- /dev/null +++ b/lib/tree-2.81/src/Makefile @@ -0,0 +1,14 @@ + +%.o: %.cc + g++ -c -I. $^ + +test1: test1.o + g++ -o test1 test1.o + +run_tests: test1 test1.req + ./test1 > test1.res + @diff test1.res test1.req + @echo "*** All tests OK ***" + +clean: + rm -f *.o *~ *.res diff --git a/lib/tree-2.81/src/simple tree.hpp b/lib/tree-2.81/src/simple tree.hpp new file mode 100644 index 0000000..5c7b54c --- /dev/null +++ b/lib/tree-2.81/src/simple tree.hpp @@ -0,0 +1,1560 @@ +// Another STL-like templated tree class. +// Revised by: Xinlin Cao(xinlincao@gmail.com) +// Revised from Kasper Peeters's implementation.(http://www.aei.mpg.de/~peekas/tree/),Kasper Peeters +//Compared to Kasper's implementation, the modifications are the following: +//# removed sibling iterator +//# added children iterator +//# removed a lot of member functions from tree and iterators +//# changed set_head() to set_root() +//# added root() member function +//# added reparent_roo() member function +//# changed implementation of operator = () +//# changed some member functions about getting iterators +//# tested all member functions +//# removed implicit conversion between different iterators +//# removed depth iterator +//# change some parameters of some functions, such as append_child, isnert_xxx, move_xxx and so on. + +// This version of tree is simpler than old one. It is robust and easy for using and understanding. +// Distributed under the GNU General Public License version 3, + + +/** + +The tree.hh library for C++ provides an STL-like container class +for n-ary trees, templated over the data stored at the +nodes. Various types of iterators are provided (post-order, +pre-order, and others). Where possible the access methods are +compatible with the STL or alternative algorithms are +available. +*/ + +#ifndef tree_hh_ +#define tree_hh_ + +#include +#include +#include +#include +#include +#include +#include + +// HP-style construct/destroy have gone from the standard, +// so here is a copy. + +namespace kp { + + template + void constructor(T1* p, T2& val) + { + new ((void *) p) T1(val); + } + + template + void constructor(T1* p) + { + new ((void *) p) T1; + } + + template + void destructor(T1* p) + { + p->~T1(); + } + +} + +/// A node in the tree, combining links to other nodes as well as the actual data. +template +class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. +public: + tree_node_ *parent; + tree_node_ *first_child, *last_child; + tree_node_ *prev_sibling, *next_sibling; + T data; +}; // __attribute__((packed)); + +template > > +class tree { +protected: + typedef tree_node_ tree_node; +public: + /// Value of the data stored at a node. + typedef T value_type; + + class iterator_base; + class pre_order_iterator; + class post_order_iterator; + class children_iterator; + class leaf_iterator; + + tree(); + tree(const T&); + tree(const tree&); + ~tree(); + tree& operator=(const tree&); + + /// Base class for iterators, only pointers stored, no traversal logic. +#ifdef __SGI_STL_PORT + class iterator_base : public stlport::bidirectional_iterator { +#else + class iterator_base { +#endif + public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator_base(); + iterator_base(tree_node *); + + T& operator*() const; + T* operator->() const; + + /// Number of children of the node pointed to by the iterator. + unsigned int number_of_children() const; + + children_iterator begin_children_iterator() const; + children_iterator end_children_iterator() const; + + tree_node *node; + }; + + /// Depth-first iterator, first accessing the node, then its children. + class pre_order_iterator : public iterator_base { + public: + pre_order_iterator(); + pre_order_iterator(tree_node *); + + bool operator==(const pre_order_iterator&) const; + bool operator!=(const pre_order_iterator&) const; + pre_order_iterator& operator++(); + pre_order_iterator& operator--(); + pre_order_iterator operator++(int); + pre_order_iterator operator--(int); + pre_order_iterator& operator+=(unsigned int); + pre_order_iterator& operator-=(unsigned int); + }; + + /// Depth-first iterator, first accessing the children, then the node itself. + class post_order_iterator : public iterator_base { + public: + post_order_iterator(); + post_order_iterator(tree_node *); + + bool operator==(const post_order_iterator&) const; + bool operator!=(const post_order_iterator&) const; + post_order_iterator& operator++(); + post_order_iterator& operator--(); + post_order_iterator operator++(int); + post_order_iterator operator--(int); + post_order_iterator& operator+=(unsigned int); + post_order_iterator& operator-=(unsigned int); + + /// Set iterator to the first child as deep as possible down the tree. + void descend_all(); + }; + + /// Breadth-first iterator, using a queue + class breadth_first_queued_iterator : public iterator_base { + public: + breadth_first_queued_iterator(); + breadth_first_queued_iterator(tree_node *); + + bool operator==(const breadth_first_queued_iterator&) const; + bool operator!=(const breadth_first_queued_iterator&) const; + breadth_first_queued_iterator& operator++(); + breadth_first_queued_iterator operator++(int); + breadth_first_queued_iterator& operator+=(unsigned int); + + private: + std::queue traversal_queue; + }; + + /// Iterator which traverses only the nodes which are siblings of each other. + class children_iterator : public iterator_base { + public: + children_iterator(); + children_iterator(tree_node *); + + bool operator==(const children_iterator&) const; + bool operator!=(const children_iterator&) const; + children_iterator& operator++(); + children_iterator& operator--(); + children_iterator operator++(int); + children_iterator operator--(int); + children_iterator& operator+=(unsigned int); + children_iterator& operator-=(unsigned int); + + tree_node *range_first() const; + tree_node *range_last() const; + tree_node *parent_; + private: + void set_parent_(); + }; + + /// Iterator which traverses only the leaves. + class leaf_iterator : public iterator_base { + public: + leaf_iterator(); + leaf_iterator(tree_node *, tree_node *top); + + bool operator==(const leaf_iterator&) const; + bool operator!=(const leaf_iterator&) const; + leaf_iterator& operator++(); + leaf_iterator& operator--(); + leaf_iterator operator++(int); + leaf_iterator operator--(int); + leaf_iterator& operator+=(unsigned int); + leaf_iterator& operator-=(unsigned int); + private: + tree_node *top_node; + }; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator root() const; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator begin_pre_order_iterator(const iterator_base&) const; + /// Return iterator to the end of the tree. + inline pre_order_iterator end_pre_order_iterator(const iterator_base&) const; + /// Return post-order iterator to the beginning of the tree. + post_order_iterator begin_post_order_iterator(const iterator_base&) const; + /// Return post-order end iterator of the tree. + post_order_iterator end_post_order_iterator(const iterator_base&) const; + + + /// Return breadth-first iterator based on a iterator. + breadth_first_queued_iterator begin_breadth_first_iterator(const iterator_base&) const; + /// Return breadth-first end iterator. + breadth_first_queued_iterator end_breadth_first_iterator(const iterator_base&) const; + + + /// Return children iterator to the first child of given node. + children_iterator begin_children_iterator(const iterator_base&) const; + /// Return children end iterator for children of given node. + children_iterator end_children_iterator(const iterator_base&) const; + + /// Return leaf iterator to the first leaf of the subtree at the given node. + leaf_iterator begin_leaf_iterator(const iterator_base& top) const; + /// Return leaf end iterator for the subtree at the given node. + leaf_iterator end_leaf_iterator(const iterator_base& top) const; + + /// Return iterator to the parent of a node. + pre_order_iterator parent(const iterator_base&); + /// Return iterator to the previous sibling of a node. + pre_order_iterator previous_sibling(const iterator_base&) const; + /// Return iterator to the next sibling of a node. + pre_order_iterator next_sibling(const iterator_base&) const; + + /// Erase all nodes of the tree. + void clear(); + /// Erase element at position pointed to by iterator, return incremented iterator. + template iter erase(iter); + /// Erase all children of the node pointed to by iterator. + void erase_children(const iterator_base&); + + + /// Short-hand to insert_before topmost node in otherwise empty tree. + pre_order_iterator set_root(const T& x); + + /// Insert node as last/first child of node pointed to by position. + pre_order_iterator append_child(const iterator_base& position, const T& x); + pre_order_iterator prepend_child(const iterator_base& position, const T& x); + + /// Insert node as previous sibling of node pointed to by position. + pre_order_iterator insert_before(iterator_base& position, const T& x); + /// Insert node as next sibling of node pointed to by position. + pre_order_iterator insert_after(const iterator_base& position, const T& x); + + /// set the data on position to be x. + pre_order_iterator modify_data(const iterator_base& position, const T& x); + + ///set X as the new head of the tree, the old head will be a child of new head. + pre_order_iterator reparent_root(const T& x); + + /// Move 'source' node (plus its children) to become the next sibling of 'target'. + pre_order_iterator move_after(const iterator_base& target, const iterator_base& source); + /// Move 'source' node (plus its children) to become the previous sibling of 'target'. + pre_order_iterator move_before(const iterator_base& target, const iterator_base& source); + + /// Count the total number of nodes. + size_t size() const; + /// Count the total number of nodes below the indicated node (plus one). + size_t size(const iterator_base&) const; + /// Check if tree is empty. + bool empty() const; + /// Compute the depth to the root or to a fixed other iterator. + int depth(const iterator_base&); + int depth(const iterator_base&, const iterator_base&); + /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. + int max_depth() const; + /// Determine the maximal depth of the tree with top node at the given position. + int max_depth(const iterator_base&) const; + /// Count the number of children of node at position. + unsigned int number_of_children(const iterator_base&); + /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. + bool is_valid(const iterator_base&) const; + + /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) + class iterator_base_less { + public: + bool operator()(const typename tree::iterator_base& one, + const typename tree::iterator_base& two) const + { + return one.node < two.node; + } + }; + tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid +private: + tree_node_allocator alloc_; + void head_initialise_(); + //copy the data from other.src to this.dst + void construct_children_nodes_helper_(const pre_order_iterator& dst, const tree& other, const pre_order_iterator& src); + void copy_(const tree& other); + + /// Comparator class for two nodes of a tree (used for sorting and searching). + template + class compare_nodes { + public: + compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; + + bool operator()(const tree_node *a, const tree_node *b) + { + return comp_(a->data, b->data); + } + private: + StrictWeakOrdering comp_; + }; +}; + + + +// Tree + +template +tree::tree() +{ + head_initialise_(); +} + +template +tree::tree(const T& x) +{ + head_initialise_(); + set_root(x); +} + +template +tree::~tree() +{ + clear(); + alloc_.deallocate(head,1); + alloc_.deallocate(feet,1); +} + +template +void tree::head_initialise_() +{ + + head = alloc_.allocate(1,0); // MSVC does not have default second argument + feet = alloc_.allocate(1,0); + + head->parent=0; + head->first_child=0; + head->last_child=0; + head->prev_sibling=0; //head; + head->next_sibling=feet; //head; + + feet->parent=0; + feet->first_child=0; + feet->last_child=0; + feet->prev_sibling=head; + feet->next_sibling=0; +} + +template +tree& tree::operator=(const tree& other) +{ + if (this != &other) + { + copy_(other); + } + return (*this); +} + +template +tree::tree(const tree& other) +{ + head_initialise_(); + copy_(other); +} + +template +void tree::construct_children_nodes_helper_(const pre_order_iterator& dst, const tree& other, const pre_order_iterator& src) +{ + + children_iterator childIter = other.begin_children_iterator(src); + for(; childIter != other.end_children_iterator(other.root()); ++childIter) + { + pre_order_iterator new_dst = append_child(dst,(*childIter)); + pre_order_iterator new_src = other.begin_pre_order_iterator(childIter); + construct_children_nodes_helper_(new_dst, other, new_src); + } +} + + +template +void tree::copy_(const tree& other) +{ + //check self + if (this == &other) + { + assert(0); + return; + } + clear(); + + + set_root(*other.root()); + construct_children_nodes_helper_(this->root(), other, other.root()); +} + +template +void tree::clear() +{ + if(head) + { + while(head->next_sibling!=feet) + { + erase(pre_order_iterator(head->next_sibling)); + } + } +} + +template +void tree::erase_children(const iterator_base& it) +{ + // std::cout << "erase_children " << it.node << std::endl; + if(it.node==0) return; + + tree_node *cur=it.node->first_child; + tree_node *prev=0; + + while(cur!=0) { + prev=cur; + cur=cur->next_sibling; + erase_children(pre_order_iterator(prev)); + kp::destructor(&prev->data); + alloc_.deallocate(prev,1); + } + it.node->first_child=0; + it.node->last_child=0; + // std::cout << "exit" << std::endl; +} + +template +template +iter tree::erase(iter it) +{ +#define CXL_IMP 0 +#if CXL_IMP + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ++ret; + + + children_iterator childIter = this->begin_children_iterator(it); + children_iterator childIterNext; + while(childIter != this->end_children_iterator(it)) + { + childIterNext = ++childIter; + erase(childIter); + childIter = childIterNext; + } + + + // + // + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + + kp::destructor(&cur->data); + alloc_.deallocate(cur,1); + return ret; +#else + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ++ret; + + + erase_children(it); + + + // + // + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + + kp::destructor(&cur->data); + alloc_.deallocate(cur,1); + return ret; +#endif +} + +template +typename tree::pre_order_iterator tree::root() const +{ + + return pre_order_iterator(head->next_sibling); +} + + +template +typename tree::pre_order_iterator tree::begin_pre_order_iterator(const iterator_base& pos) const +{ + + return pre_order_iterator(pos.node); +} + +template +typename tree::pre_order_iterator tree::end_pre_order_iterator(const iterator_base& pos) const +{ + + return pre_order_iterator(pos.node->next_sibling); +} + + +template +typename tree::breadth_first_queued_iterator tree::begin_breadth_first_iterator(const iterator_base& pos) const +{ + + return breadth_first_queued_iterator(pos.node); +} + +template +typename tree::breadth_first_queued_iterator tree::end_breadth_first_iterator(const iterator_base& pos) const +{ + + return breadth_first_queued_iterator(); +} + + +template +typename tree::post_order_iterator tree::begin_post_order_iterator(const iterator_base& pos) const +{ + + tree_node *tmp=pos.node; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return post_order_iterator(tmp); +} + +template +typename tree::post_order_iterator tree::end_post_order_iterator(const iterator_base& pos) const +{ + + return post_order_iterator(pos.node->next_sibling); +} + + +template +typename tree::children_iterator tree::begin_children_iterator(const iterator_base& pos) const +{ + + assert(pos.node!=0); + if(pos.node->first_child==0) { + return end_children_iterator(pos); + } + return pos.node->first_child; +} + +template +typename tree::children_iterator tree::end_children_iterator(const iterator_base& pos) const +{ + + + children_iterator ret(0); + ret.parent_=pos.node; + return ret; +} + +template +typename tree::leaf_iterator tree::begin_leaf_iterator(const iterator_base& top) const +{ + + tree_node *tmp=top.node; + while(tmp->first_child) + tmp=tmp->first_child; + return leaf_iterator(tmp, top.node); +} + +template +typename tree::leaf_iterator tree::end_leaf_iterator(const iterator_base& top) const +{ + + return leaf_iterator(top.node, top.node); +} + +template +typename tree::pre_order_iterator tree::parent(const iterator_base& position) +{ + + assert(position.node!=0); + return pre_order_iterator(position.node->parent); +} + +template +typename tree::pre_order_iterator tree::previous_sibling(const iterator_base& position) const +{ + + assert(position.node!=0); + pre_order_iterator ret(position); + ret.node=position.node->prev_sibling; + return ret; +} + +template +typename tree::pre_order_iterator tree::next_sibling(const iterator_base& position) const +{ + + assert(position.node!=0); + pre_order_iterator ret(position); + ret.node=position.node->next_sibling; + return ret; +} + +template +typename tree::pre_order_iterator tree::append_child(const iterator_base& position, const T& x) +{ + // If your program fails here you probably used 'append_child' to add the top + // node to an empty tree. From version 1.45 the top element should be added + // using 'insert_before'. See the documentation for further information, and sorry about + // the API change. + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return pre_order_iterator(tmp); +} + +template +typename tree::pre_order_iterator tree::prepend_child(const iterator_base& position, const T& x) +{ + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->first_child=tmp; + tmp->prev_sibling=0; + return pre_order_iterator(tmp); +} + + +template +typename tree::pre_order_iterator tree::set_root(const T& x) +{ + assert(head->next_sibling==feet); + + return insert_before(pre_order_iterator(feet), x); +} + +template +typename tree::pre_order_iterator tree::insert_before(iterator_base& position, const T& x) +{ + if(position.node==0) { + position.node=feet; // Backward compatibility: when calling insert_before on a null node, + // insert_before before the feet. + } + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->next_sibling=position.node; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + { + tmp->prev_sibling->next_sibling=tmp; + } + return pre_order_iterator(tmp); +} + + +template +typename tree::pre_order_iterator tree::insert_after(const iterator_base& position, const T& x) +{ + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node; + tmp->next_sibling=position.node->next_sibling; + position.node->next_sibling=tmp; + + if(tmp->next_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->last_child=tmp; + } + else { + tmp->next_sibling->prev_sibling=tmp; + } + return pre_order_iterator(tmp); +} + + +template +typename tree::pre_order_iterator tree::modify_data(const iterator_base& position, const T& x) +{ + kp::destructor(&position.node->data); + kp::constructor(&position.node->data, x); + return position; +} + +///set X as the new head of the tree, the old head will be a child of new head. +template +typename tree::pre_order_iterator tree::reparent_root(const T& x) +{ + if(head->next_sibling == feet) + { + return this->set_root(x); + } + else + { + //remember the old head + tree_node *old_head_node = head->next_sibling; + + //create a new head + insert_before(pre_order_iterator(feet), x); + + //change the tree head + tree_node *new_head_node = head->next_sibling->next_sibling; + head->next_sibling = new_head_node; + + //change the new head + new_head_node->first_child = old_head_node; + new_head_node->last_child = old_head_node; + new_head_node->next_sibling = feet; + new_head_node->prev_sibling = head; + + //change the feet + feet->prev_sibling = new_head_node; + + //change the old head + old_head_node->next_sibling = 0; + old_head_node->prev_sibling = 0; + old_head_node->parent = new_head_node; + + return begin_pre_order_iterator(root()); + } +} + +template +typename tree::pre_order_iterator tree::move_after(const iterator_base& target, const iterator_base& source) +{ + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return this->begin_pre_order_iterator(source); + if(dst->next_sibling) + if(dst->next_sibling==src) // already in the right spot + return this->begin_pre_order_iterator(source); + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; + else dst->parent->last_child=src; + src->next_sibling=dst->next_sibling; + dst->next_sibling=src; + src->prev_sibling=dst; + src->parent=dst->parent; + return pre_order_iterator(src); +} + +template +typename tree::pre_order_iterator tree::move_before(const iterator_base& target, const iterator_base& source) +{ + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return this->begin_pre_order_iterator(source); + if(dst->prev_sibling) + if(dst->prev_sibling==src) // already in the right spot + return this->begin_pre_order_iterator(source); + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; + else dst->parent->first_child=src; + src->prev_sibling=dst->prev_sibling; + dst->prev_sibling=src; + src->next_sibling=dst; + src->parent=dst->parent; + return pre_order_iterator(src); +} + + +template +size_t tree::size() const +{ + size_t i=0; + pre_order_iterator it=begin_pre_order_iterator(), eit=end_pre_order_iterator(); + while(it!=eit) { + ++i; + ++it; + } + return i; +} + +template +size_t tree::size(const iterator_base& top) const +{ + size_t i=0; + pre_order_iterator it=top, eit=top; + ++eit; + while(it!=eit) { + ++i; + ++it; + } + return i; +} + +template +bool tree::empty() const +{ + pre_order_iterator it=begin_pre_order_iterator(), eit=end_pre_order_iterator(); + return (it==eit); +} + +template +int tree::depth(const iterator_base& it) +{ + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0) { + pos=pos->parent; + ++ret; + } + return ret; +} + +template +int tree::depth(const iterator_base& it, const iterator_base& root) +{ + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0 && pos!=root.node) { + pos=pos->parent; + ++ret; + } + return ret; +} + +template +int tree::max_depth() const +{ + int maxd=-1; + for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) + { + + maxd=std::max(maxd, max_depth(it)); + } + + return maxd; +} + + +template +int tree::max_depth(const iterator_base& pos) const +{ + + tree_node *tmp=pos.node; + + if(tmp==0 || tmp==head || tmp==feet) return -1; + + int curdepth=0, maxdepth=0; + while(true) { // try to walk the bottom of the tree + while(tmp->first_child==0) + { + if(tmp==pos.node) return maxdepth; + if(tmp->next_sibling==0) + { + // try to walk up and then right again + do { + tmp=tmp->parent; + if(tmp==0) return maxdepth; + --curdepth; + } while(tmp->next_sibling==0); + } + + + + if(tmp==pos.node) return maxdepth; + tmp=tmp->next_sibling; + } + + tmp=tmp->first_child; + ++curdepth; + maxdepth=std::max(curdepth, maxdepth); + } +} + +template +unsigned int tree::number_of_children(const iterator_base& it) +{ + tree_node *pos=it.node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + // while(pos!=it.node->last_child) { + // ++ret; + // pos=pos->next_sibling; + // } + while((pos=pos->next_sibling)) + ++ret; + return ret; +} + +template +bool tree::is_valid(const iterator_base& it) const +{ + if(it.node==0 || it.node==feet || it.node==head) return false; + else return true; +} + +// Iterator base + +template +tree::iterator_base::iterator_base() +: node(0) +{ +} + +template +tree::iterator_base::iterator_base(tree_node *tn) +: node(tn) +{ +} + +template +T& tree::iterator_base::operator*() const +{ + return node->data; +} + +template +T* tree::iterator_base::operator->() const +{ + return &(node->data); +} + +template +bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::post_order_iterator::operator==(const post_order_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +bool tree::children_iterator::operator!=(const children_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::children_iterator::operator==(const children_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::leaf_iterator::operator==(const leaf_iterator& other) const +{ + if(other.node==this->node && other.top_node==this->top_node) return true; + else return false; +} + + +template +typename tree::children_iterator tree::iterator_base::begin_children_iterator() const +{ + if(node->first_child==0) + return end_children_iterator(); + + children_iterator ret(node->first_child); + ret.parent_=this->node; + return ret; +} + +template +typename tree::children_iterator tree::iterator_base::end_children_iterator() const +{ + children_iterator ret(0); + ret.parent_=node; + return ret; +} + +template +unsigned int tree::iterator_base::number_of_children() const +{ + tree_node *pos=node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + while(pos!=node->last_child) { + ++ret; + pos=pos->next_sibling; + } + return ret; +} + + + +// Pre-order iterator + +template +tree::pre_order_iterator::pre_order_iterator() +: iterator_base(0) +{ +} + +template +tree::pre_order_iterator::pre_order_iterator(tree_node *tn) +: iterator_base(tn) +{ +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() +{ + assert(this->node!=0); + if(this->node->first_child != 0) { + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + this->node=this->node->next_sibling; + } + return *this; + + +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() +{ + assert(this->node!=0); + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + } + else { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + return *this; + + +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) +{ + pre_order_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) +{ + pre_order_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + + + +// Post-order iterator + +template +tree::post_order_iterator::post_order_iterator() +: iterator_base(0) +{ +} + +template +tree::post_order_iterator::post_order_iterator(tree_node *tn) +: iterator_base(tn) +{ +} + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator++() +{ + assert(this->node!=0); + if(this->node->next_sibling==0) { + this->node=this->node->parent; + } + else { + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; + +} + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator--() +{ + assert(this->node!=0); + if(this->node->last_child==0) + { + + while(this->node->prev_sibling==0) + { + this->node=this->node->parent; + } + this->node=this->node->prev_sibling; + } + else + { + this->node=this->node->last_child; + } + return *this; + +} + +template +typename tree::post_order_iterator tree::post_order_iterator::operator++(int) +{ + post_order_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::post_order_iterator tree::post_order_iterator::operator--(int) +{ + post_order_iterator copy = *this; + --(*this); + return copy; +} + + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + +template +void tree::post_order_iterator::descend_all() +{ + assert(this->node!=0); + while(this->node->first_child) + this->node=this->node->first_child; +} + + +// Breadth-first iterator + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator() +: iterator_base() +{ +} + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) +: iterator_base(tn) +{ + traversal_queue.push(tn); +} + +template +bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() +{ + assert(this->node!=0); + + // Add child nodes and pop current node + children_iterator sib=this->begin_children_iterator(); + while(sib!=this->end_children_iterator()) { + traversal_queue.push(sib.node); + ++sib; + } + traversal_queue.pop(); + if(traversal_queue.size()>0) + this->node=traversal_queue.front(); + else + this->node=0; + return (*this); +} + +template +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) +{ + breadth_first_queued_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +// Sibling iterator + +template +tree::children_iterator::children_iterator() +: iterator_base() +{ + set_parent_(); +} + +template +tree::children_iterator::children_iterator(tree_node *tn) +: iterator_base(tn) +{ + set_parent_(); +} + +template +void tree::children_iterator::set_parent_() +{ + parent_=0; + if(this->node==0) return; + if(this->node->parent!=0) + parent_=this->node->parent; +} + +template +typename tree::children_iterator& tree::children_iterator::operator++() +{ + if(this->node) + this->node=this->node->next_sibling; + return *this; +} + +template +typename tree::children_iterator& tree::children_iterator::operator--() +{ + if(this->node) this->node=this->node->prev_sibling; + else { + assert(parent_); + this->node=parent_->last_child; + } + return *this; +} + +template +typename tree::children_iterator tree::children_iterator::operator++(int) +{ + children_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::children_iterator tree::children_iterator::operator--(int) +{ + children_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::children_iterator& tree::children_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::children_iterator& tree::children_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + +template +typename tree::tree_node *tree::children_iterator::range_first() const +{ + tree_node *tmp=parent_->first_child; + return tmp; +} + +template +typename tree::tree_node *tree::children_iterator::range_last() const +{ + return parent_->last_child; +} + +// Leaf iterator + +template +tree::leaf_iterator::leaf_iterator() +: iterator_base(0), top_node(0) +{ +} + +template +tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) +: iterator_base(tn), top_node(top) +{ +} + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator++() +{ + assert(this->node!=0); + if(this->node->first_child!=0) { // current node is no longer leaf (children got added) + while(this->node->first_child) + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node != 0 && this->node==top_node) return *this; + } + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; + +} + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator--() +{ + assert(this->node!=0); + while (this->node->prev_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node !=0 && this->node==top_node) return *this; + } + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + return *this; +} + +template +typename tree::leaf_iterator tree::leaf_iterator::operator++(int) +{ + leaf_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::leaf_iterator tree::leaf_iterator::operator--(int) +{ + leaf_iterator copy = *this; + --(*this); + return copy; +} + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + +#endif diff --git a/lib/tree-2.81/src/test1.cc b/lib/tree-2.81/src/test1.cc new file mode 100644 index 0000000..5bb2fdf --- /dev/null +++ b/lib/tree-2.81/src/test1.cc @@ -0,0 +1,18 @@ +#include "tree.hh" +#include "tree_util.hh" + +int main(int, char **) + { + tree tr; + + tr.insert(tr.begin(), 1); + tree::iterator i2 = tr.insert(tr.end(), 2); + tree::iterator i3 = tr.insert(tr.end(), 3); + tr.append_child(i2, 21); + tr.append_child(i3, 31); + tree::iterator i4 = tr.insert(tr.end(), 4); + + kptree::print_tree_bracketed(tr, std::cout); + + std::cout << std::endl; + } diff --git a/lib/tree-2.81/src/test1.req b/lib/tree-2.81/src/test1.req new file mode 100644 index 0000000..e2e3a45 --- /dev/null +++ b/lib/tree-2.81/src/test1.req @@ -0,0 +1,4 @@ +1 +2(21) +3(31) +4 diff --git a/lib/tree-2.81/src/test_tree.cc b/lib/tree-2.81/src/test_tree.cc new file mode 100644 index 0000000..6f1bf1c --- /dev/null +++ b/lib/tree-2.81/src/test_tree.cc @@ -0,0 +1,378 @@ +/* + + STL-like templated tree class; test program. + Copyright (C) 2001-2009 Kasper Peeters + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "tree.hh" +#include "tree_util.hh" + +#include +#include +#include +#include +#include +#include +#include + +/* + + Simple test program for the tree.hh class library. Run it and see + what happens. Or, if you want to see that it does not leak memory, + run it like + + ./test_tree 10000 >/dev/null + + or some other large number and have 'top' running in a different + shell. This will run the tests 10000 times, creating and destroying + the trees for every iteration of the loop. + + */ + +bool truefunc(std::string& one, std::string& two) + { +// std::cout << "comparing " << one << "==" << two << std::endl; + return true; + } + +void print_tree(const tree& tr, tree::pre_order_iterator it, tree::pre_order_iterator end) + { + if(!tr.is_valid(it)) return; + int rootdepth=tr.depth(it); + std::cout << "-----" << std::endl; + while(it!=end) { + for(int i=0; i& tr, tree::post_order_iterator it, tree::post_order_iterator end) + { + int rootdepth=tr.depth(it); + std::cout << "-----" << std::endl; + while(it!=end) { + for(int i=0; i& tr, tree::pre_order_iterator it, tree::pre_order_iterator end) + { + --it; + int rootdepth=0;//tr.depth(it); + std::cout << "-----" << std::endl; + while(1==1) { + for(int i=0; i& tr, tree::post_order_iterator it, tree::post_order_iterator end) + { + --it; + int rootdepth=0;//tr.depth(it); + std::cout << "-----" << std::endl; + while(1==1) { + for(int i=0; i1) + maxloop=atoi(argv[1]); + + for(unsigned int j=0; j tr9; + tr9.set_head("hi"); + tr9.insert(tr9.begin().begin(), "0"); + tr9.insert(tr9.begin().begin(), "1"); + print_tree(tr9, tr9.begin(), tr9.end()); + + + tree tr; + tree::pre_order_iterator html, body, h1, h3, bh1, mv1; + + std::cout << "empty tree to begin with:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + html=tr.insert(tr.begin(), "html"); + tr.insert(html,"extra"); +// tr.insert(html,"zextra2"); + body=tr.append_child(html, "body"); + h1 =tr.append_child(body, "h1"); + std::cout << tr.index(h1) << std::endl; + bh1 =tr.insert(h1,"before h1"); + tr.append_child(h1, "some text"); + tree::sibling_iterator more_text=tr.append_child(body, "more text"); + + std::cout << " 'more text' is sibling " << tr.index(more_text) << " in its sibling range" << std::endl; + + std::cout << "filled tree:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + std::cout << "filled tree, post-order traversal:" << std::endl; + print_tree_post(tr, tr.begin_post(), tr.end_post()); + + tr.swap(bh1); + std::cout << "swapped elements:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + tr.swap(h1); + std::cout << "swapped back:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + tree copytree(h1); + std::cout << "copied tree:" << std::endl; + print_tree(copytree, copytree.begin(), copytree.end()); + + // Now test the STL algorithms + std::cout << "result of search for h1 and kasper:" << std::endl; + tree::pre_order_iterator it; + it=std::find(tr.begin(),tr.end(),std::string("h1")); + if(it!=tr.end()) print_tree(tr, it, tr.next_sibling(it)); + else std::cout << "h1 not found" << std::endl; + it=std::find(tr.begin(),tr.end(), std::string("kasper")); + if(it!=tr.end()) print_tree(tr, it, tr.next_sibling(it)); + else std::cout << "kasper not found" << std::endl; + std::cout << std::endl; + + // remove the h1, replace it with new subtree + tree replacement; + h3 =replacement.insert(replacement.begin(), "h3"); + replacement.append_child(h3, "text in h3"); + std::cout << "replacement tree:" << std::endl; + print_tree(replacement, replacement.begin(), replacement.end()); + print_tree(tr, tr.begin(), tr.end()); + h1=tr.replace(tree::sibling_iterator(h1), tr.next_sibling(h1), + tree::sibling_iterator(h3), tr.next_sibling(h3)); + std::cout << "filled tree with replacement done:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + // replace h3 node while keeping children + h1=tr.replace(h1, ""); + print_tree(tr, tr.begin(), tr.end()); + + // add a sibling to the head + tr.insert_after(h1, "more"); + + // Copy object. + tree tr2=tr; + print_tree(tr2, tr2.begin(), tr2.end()); + tree tr3(tr); + + // reparent "before h1" to h3 node + tr.reparent(h1, bh1, tr.next_sibling(bh1)); + std::cout << "moved content:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + // iterate over children only + tree::sibling_iterator ch=tr.begin(h1); + std::cout << "children of h1:" << std::endl; + while(ch!=tr.end(h1)) { + std::cout << (*ch) << std::endl; + ++ch; + } + std::cout << std::endl; + + // flatten the h3 node + tr.flatten(h1); + std::cout << "flattened (at h3) tree:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + // Erase the subtree of tr below body. + tr.erase_children(body); + std::cout << "children of body erased:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + it=std::find(tr.begin(),tr.end(),"h1"); + if(it!=tr.end()) print_tree(tr, it, tr.next_sibling(it)); + else std::cout << "h1 not found" << std::endl; + + // Erase everything + tr.erase(tr.begin()); + std::cout << "erased tree:" << std::endl; + print_tree(tr, tr.begin(), tr.end()); + + // The copies are deep, ie. all nodes have been copied. + std::cout << "copies still exist:" << std::endl; + print_tree(tr2, tr2.begin(), tr2.end()); + print_tree(tr3, tr3.begin(), tr3.end()); + + // Test comparison + std::cout << "testing comparison functions:" << std::endl; + std::cout << std::equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 1)" << std::endl; + // modify content but not structure + tree::pre_order_iterator fl3=tr3.begin(); + fl3+=4; // pointing to "" node + std::cout << (*fl3) << std::endl; + std::string tmpfl3=(*fl3); + (*fl3)="modified"; + std::cout << std::equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 0)" << std::endl; + std::cout << tr2.equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 0)" << std::endl; + std::cout << tr2.equal(tr2.begin(), tr2.end(), tr3.begin(), truefunc) + << " (should be 1)" << std::endl; + // modify tr3 structure (but not content) + (*fl3)=tmpfl3; + tr3.flatten(fl3); + std::cout << "tree flattened, test again" << std::endl; + print_tree(tr3, tr3.begin(), tr3.end()); + + // Test comparison again + std::cout << tr2.equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 0)" << std::endl; + std::cout << std::equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 1)" << std::endl; + // Change content + (*fl3)="modified"; + // Test comparison again + std::cout << std::equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 0)" << std::endl; + std::cout << tr2.equal(tr2.begin(), tr2.end(), tr3.begin(), std::equal_to()) + << " (should be 0)" << std::endl; + + // Testing sort. First add a subtree to one leaf + tree::pre_order_iterator txx3=tr3.begin(); + txx3+=5; + tr3.append_child(txx3,"ccc"); + tr3.append_child(txx3,"bbb"); + tr3.append_child(txx3,"bbb"); + tr3.append_child(txx3,"aaa"); + std::less comp; + tree::pre_order_iterator bdy=tr3.begin(); + bdy+=2; + assert(tr.is_valid(bdy)); + std::cout << "unsorted subtree:" << std::endl; + print_tree(tr3, tr3.begin(), tr3.end()); + tree::sibling_iterator sortit1=tr3.begin(bdy), sortit2=tr3.begin(bdy); + sortit1+=2; + sortit2+=4; + assert(tr.is_valid(sortit1)); + assert(tr.is_valid(sortit2)); + std::cout << "partially sorted subtree: (" + << "sorted from " << (*sortit1) << " to " + << (*sortit2) << ", excluding the last element)" << std::endl; + + + mv1=tr3.begin(); + ++mv1; + tr3.sort(sortit1, sortit2); + print_tree(tr3, tr3.begin(), tr3.end()); + tr3.sort(tr3.begin(bdy), tr3.end(bdy), comp, true); // false: no sorting of subtrees +// Sorting the entire tree, level by level, is much simpler: +// tr3.sort(tr3.begin(), tr3.end(), true); + std::cout << "sorted subtree:" << std::endl; + print_tree(tr3, tr3.begin(), tr3.end()); + + // Michael's problem +// std::cout << mv1.node << ", " << tr3.feet << ", " << tr3.feet->prev_sibling << std::endl; +// std::cout << mv1.node->next_sibling << ", " << tr3.feet->prev_sibling << ", " << tr3.end().node << std::endl; +// tr3.sort(tr3.begin(), tr3.end(), true); +// std::cout << mv1.node << ", " << tr3.feet << ", " << tr3.feet->prev_sibling << std::endl; +// std::cout << mv1.node->next_sibling << ", " << tr3.feet->prev_sibling << ", " << tr3.end().node << std::endl; +// print_tree(tr3, tr3.begin(), tr3.end()); +// tr3.sort(tr3.begin(), tr3.end(), true); +// std::cout << mv1.node << ", " << tr3.feet << ", " << tr3.feet->prev_sibling << std::endl; +// std::cout << mv1.node->next_sibling << ", " << tr3.feet->prev_sibling << ", " << tr3.end().node << std::endl; +// print_tree(tr3, tr3.begin(), tr3.end()); +// return 1; + + // Test merge algorithm. + std::cout << "test merge" << std::endl; + tree mtree; + tree::pre_order_iterator mt1, mt2, mt3; + mt1=mtree.insert(mtree.begin(),"html"); + mt2=mtree.append_child(mt1,"head"); + mt3=mtree.append_child(mt1,"body"); +// Adding it without head having any children tests whether we can +// insert at the end of an empty list of children. + mtree.append_child(mt2,"title"); + mtree.append_child(mt3,"h1"); + mtree.append_child(mt3,"h1"); + + tree mtBree; + tree::pre_order_iterator mtB1, mtB2; + mtB1=mtBree.insert(mtBree.begin(),"head"); + mtB2=mtBree.append_child(mtB1,"another title"); + print_tree(mtree, mtree.begin(), mtree.end()); + print_tree(mtBree, mtBree.begin(), mtBree.end()); + + mtree.merge(mtree.begin(), mtree.end(), mtBree.begin(), mtBree.end(), true); + print_tree(mtree, mtree.begin(), mtree.end()); + mtree.merge(mtree.begin(mtree.begin()), mtree.end(mtree.begin()), mtBree.begin(), mtBree.end(), true); + print_tree(mtree, mtree.begin(), mtree.end()); + + // Print tree in reverse (test operator--) + print_tree_rev(mtree, mtree.end(), mtree.begin()); + print_tree_rev_post(mtree, mtree.end_post(), mtree.begin_post()); + + // Breadth-first + tree bft; + tree::iterator bfB,bfC,bfD; + bft.set_head("A"); + bfB=bft.append_child(bft.begin(), "B"); + bfC=bft.append_child(bft.begin(), "C"); + bfD=bft.append_child(bft.begin(), "D"); + bft.append_child(bfB, "E"); + bft.append_child(bfB, "F"); + bft.append_child(bfC, "G"); + bft.append_child(bfC, "H"); + bft.append_child(bfD, "I"); + tree::breadth_first_queued_iterator bfq=bft.begin_breadth_first(); + while(bfq!=bft.end_breadth_first()) { + std::cout << *bfq << std::endl; + ++bfq; + } + + print_tree(bft, bft.begin(), bft.end()); + bft.wrap(bfD, "wrap"); + print_tree(bft, bft.begin(), bft.end()); + + tree::leaf_iterator li=tr.begin_leaf(bfC); + while(li!=tr.end_leaf(bfC)) { + std::cout << *li << std::endl; + ++li; + } + +// tree testfixed; +// testfixed.insert(testfixed.begin(), "one"); +// testfixed.insert(testfixed.begin(), "two"); +// testfixed.insert(testfixed.begin(), "three"); +// tree::fixed_depth_iterator fit=testfixed.begin(); +// while(testfixed.is_valid(fit)) { +// std::cout << *fit << std::endl; +// ++fit; +// } + } + } diff --git a/lib/tree-2.81/src/test_tree.output b/lib/tree-2.81/src/test_tree.output new file mode 100644 index 0000000..f6b0848 --- /dev/null +++ b/lib/tree-2.81/src/test_tree.output @@ -0,0 +1,311 @@ +empty tree to begin with: +0 + 'more text' is sibling 2 in its sibling range +filled tree: +----- +extra +html + body + before h1 + h1 + some text + more text +----- +filled tree, post-order traversal: +----- +extra + before h1 + some text + h1 + more text + body +html +----- +swapped elements: +----- +extra +html + body + h1 + some text + before h1 + more text +----- +swapped back: +----- +extra +html + body + before h1 + h1 + some text + more text +----- +copied tree: +----- +h1 + some text +----- +result of search for h1 and kasper: +----- +h1 + some text +----- +kasper not found + +replacement tree: +----- +h3 + text in h3 +----- +----- +extra +html + body + before h1 + h1 + some text + more text +----- +filled tree with replacement done: +----- +extra +html + body + before h1 + h3 + text in h3 + more text +----- +----- +extra +html + body + before h1 + + text in h3 + more text +----- +----- +extra +html + body + before h1 + + text in h3 + more + more text +----- +moved content: +----- +extra +html + body + + text in h3 + before h1 + more + more text +----- +children of h1: +text in h3 +before h1 + +flattened (at h3) tree: +----- +extra +html + body + + text in h3 + before h1 + more + more text +----- +children of body erased: +----- +extra +html + body +----- +h1 not found +erased tree: +----- +html + body +----- +copies still exist: +----- +extra +html + body + before h1 + + text in h3 + more + more text +----- +----- +extra +html + body + before h1 + + text in h3 + more + more text +----- +testing comparison functions: +1 (should be 1) + +0 (should be 0) +0 (should be 0) +1 (should be 1) +tree flattened, test again +----- +extra +html + body + before h1 + + text in h3 + more + more text +----- +0 (should be 0) +1 (should be 1) +0 (should be 0) +0 (should be 0) +unsorted subtree: +----- +extra +html + body + before h1 + modified + text in h3 + ccc + bbb + bbb + aaa + more + more text +----- +partially sorted subtree: (sorted from text in h3 to more text, excluding the last element) +----- +extra +html + body + before h1 + modified + more + text in h3 + ccc + bbb + bbb + aaa + more text +----- +sorted subtree: +----- +extra +html + body + before h1 + modified + more + more text + text in h3 + aaa + bbb + bbb + ccc +----- +test merge +----- +html + head + title + body + h1 + h1 +----- +----- +head + another title +----- +----- +html + head + title + body + h1 + h1 +head + another title +----- +----- +html + head + title + another title + body + h1 + h1 +head + another title +----- +----- + another title +head + h1 + h1 + body + another title + title + head +html +----- +----- +head + another title +html + body + h1 + h1 + head + another title + title +----- +A +B +C +D +E +F +G +H +I +----- +A + B + E + F + C + G + H + D + I +----- +----- +A + B + E + F + C + G + H + wrap + D + I +----- diff --git a/lib/tree-2.81/src/tree.hh b/lib/tree-2.81/src/tree.hh new file mode 100644 index 0000000..b2f3005 --- /dev/null +++ b/lib/tree-2.81/src/tree.hh @@ -0,0 +1,2786 @@ + +// STL-like templated tree class. +// +// Copyright (C) 2001-2011 Kasper Peeters +// Distributed under the GNU General Public License version 3. +// +// When used together with the htmlcxx library to create +// HTML::Node template instances, the GNU Lesser General Public +// version 2 applies. Special permission to use tree.hh under +// the LGPL for other projects can be requested from the author. + +/** \mainpage tree.hh + \author Kasper Peeters + \version 2.81 + \date 23-Aug-2011 + \see http://tree.phi-sci.com/ + \see http://tree.phi-sci.com/ChangeLog + + The tree.hh library for C++ provides an STL-like container class + for n-ary trees, templated over the data stored at the + nodes. Various types of iterators are provided (post-order, + pre-order, and others). Where possible the access methods are + compatible with the STL or alternative algorithms are + available. +*/ + + +#ifndef tree_hh_ +#define tree_hh_ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/// A node in the tree, combining links to other nodes as well as the actual data. +template +class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. + public: + tree_node_(); + tree_node_(const T&); + + tree_node_ *parent; + tree_node_ *first_child, *last_child; + tree_node_ *prev_sibling, *next_sibling; + T data; +}; // __attribute__((packed)); + +template +tree_node_::tree_node_() + : parent(0), first_child(0), last_child(0), prev_sibling(0), next_sibling(0) + { + } + +template +tree_node_::tree_node_(const T& val) + : parent(0), first_child(0), last_child(0), prev_sibling(0), next_sibling(0), data(val) + { + } + +template > > +class tree { + protected: + typedef tree_node_ tree_node; + public: + /// Value of the data stored at a node. + typedef T value_type; + + class iterator_base; + class pre_order_iterator; + class post_order_iterator; + class sibling_iterator; + class leaf_iterator; + + tree(); + tree(const T&); + tree(const iterator_base&); + tree(const tree&); + ~tree(); + tree& operator=(const tree&); + + /// Base class for iterators, only pointers stored, no traversal logic. +#ifdef __SGI_STL_PORT + class iterator_base : public stlport::bidirectional_iterator { +#else + class iterator_base { +#endif + public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator_base(); + iterator_base(tree_node *); + + T& operator*() const; + T* operator->() const; + + /// When called, the next increment/decrement skips children of this node. + void skip_children(); + void skip_children(bool skip); + /// Number of children of the node pointed to by the iterator. + unsigned int number_of_children() const; + + sibling_iterator begin() const; + sibling_iterator end() const; + + tree_node *node; + protected: + bool skip_current_children_; + }; + + /// Depth-first iterator, first accessing the node, then its children. + class pre_order_iterator : public iterator_base { + public: + pre_order_iterator(); + pre_order_iterator(tree_node *); + pre_order_iterator(const iterator_base&); + pre_order_iterator(const sibling_iterator&); + + bool operator==(const pre_order_iterator&) const; + bool operator!=(const pre_order_iterator&) const; + pre_order_iterator& operator++(); + pre_order_iterator& operator--(); + pre_order_iterator operator++(int); + pre_order_iterator operator--(int); + pre_order_iterator& operator+=(unsigned int); + pre_order_iterator& operator-=(unsigned int); + }; + + /// Depth-first iterator, first accessing the children, then the node itself. + class post_order_iterator : public iterator_base { + public: + post_order_iterator(); + post_order_iterator(tree_node *); + post_order_iterator(const iterator_base&); + post_order_iterator(const sibling_iterator&); + + bool operator==(const post_order_iterator&) const; + bool operator!=(const post_order_iterator&) const; + post_order_iterator& operator++(); + post_order_iterator& operator--(); + post_order_iterator operator++(int); + post_order_iterator operator--(int); + post_order_iterator& operator+=(unsigned int); + post_order_iterator& operator-=(unsigned int); + + /// Set iterator to the first child as deep as possible down the tree. + void descend_all(); + }; + + /// Breadth-first iterator, using a queue + class breadth_first_queued_iterator : public iterator_base { + public: + breadth_first_queued_iterator(); + breadth_first_queued_iterator(tree_node *); + breadth_first_queued_iterator(const iterator_base&); + + bool operator==(const breadth_first_queued_iterator&) const; + bool operator!=(const breadth_first_queued_iterator&) const; + breadth_first_queued_iterator& operator++(); + breadth_first_queued_iterator operator++(int); + breadth_first_queued_iterator& operator+=(unsigned int); + + private: + std::queue traversal_queue; + }; + + /// The default iterator types throughout the tree class. + typedef pre_order_iterator iterator; + typedef breadth_first_queued_iterator breadth_first_iterator; + + /// Iterator which traverses only the nodes at a given depth from the root. + class fixed_depth_iterator : public iterator_base { + public: + fixed_depth_iterator(); + fixed_depth_iterator(tree_node *); + fixed_depth_iterator(const iterator_base&); + fixed_depth_iterator(const sibling_iterator&); + fixed_depth_iterator(const fixed_depth_iterator&); + + bool operator==(const fixed_depth_iterator&) const; + bool operator!=(const fixed_depth_iterator&) const; + fixed_depth_iterator& operator++(); + fixed_depth_iterator& operator--(); + fixed_depth_iterator operator++(int); + fixed_depth_iterator operator--(int); + fixed_depth_iterator& operator+=(unsigned int); + fixed_depth_iterator& operator-=(unsigned int); + + tree_node *top_node; + }; + + /// Iterator which traverses only the nodes which are siblings of each other. + class sibling_iterator : public iterator_base { + public: + sibling_iterator(); + sibling_iterator(tree_node *); + sibling_iterator(const sibling_iterator&); + sibling_iterator(const iterator_base&); + + bool operator==(const sibling_iterator&) const; + bool operator!=(const sibling_iterator&) const; + sibling_iterator& operator++(); + sibling_iterator& operator--(); + sibling_iterator operator++(int); + sibling_iterator operator--(int); + sibling_iterator& operator+=(unsigned int); + sibling_iterator& operator-=(unsigned int); + + tree_node *range_first() const; + tree_node *range_last() const; + tree_node *parent_; + private: + void set_parent_(); + }; + + /// Iterator which traverses only the leaves. + class leaf_iterator : public iterator_base { + public: + leaf_iterator(); + leaf_iterator(tree_node *, tree_node *top=0); + leaf_iterator(const sibling_iterator&); + leaf_iterator(const iterator_base&); + + bool operator==(const leaf_iterator&) const; + bool operator!=(const leaf_iterator&) const; + leaf_iterator& operator++(); + leaf_iterator& operator--(); + leaf_iterator operator++(int); + leaf_iterator operator--(int); + leaf_iterator& operator+=(unsigned int); + leaf_iterator& operator-=(unsigned int); + private: + tree_node *top_node; + }; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator begin() const; + /// Return iterator to the end of the tree. + inline pre_order_iterator end() const; + /// Return post-order iterator to the beginning of the tree. + post_order_iterator begin_post() const; + /// Return post-order end iterator of the tree. + post_order_iterator end_post() const; + /// Return fixed-depth iterator to the first node at a given depth from the given iterator. + fixed_depth_iterator begin_fixed(const iterator_base&, unsigned int) const; + /// Return fixed-depth end iterator. + fixed_depth_iterator end_fixed(const iterator_base&, unsigned int) const; + /// Return breadth-first iterator to the first node at a given depth. + breadth_first_queued_iterator begin_breadth_first() const; + /// Return breadth-first end iterator. + breadth_first_queued_iterator end_breadth_first() const; + /// Return sibling iterator to the first child of given node. + sibling_iterator begin(const iterator_base&) const; + /// Return sibling end iterator for children of given node. + sibling_iterator end(const iterator_base&) const; + /// Return leaf iterator to the first leaf of the tree. + leaf_iterator begin_leaf() const; + /// Return leaf end iterator for entire tree. + leaf_iterator end_leaf() const; + /// Return leaf iterator to the first leaf of the subtree at the given node. + leaf_iterator begin_leaf(const iterator_base& top) const; + /// Return leaf end iterator for the subtree at the given node. + leaf_iterator end_leaf(const iterator_base& top) const; + + /// Return iterator to the parent of a node. + template static iter parent(iter); + /// Return iterator to the previous sibling of a node. + template iter previous_sibling(iter) const; + /// Return iterator to the next sibling of a node. + template iter next_sibling(iter) const; + /// Return iterator to the next node at a given depth. + template iter next_at_same_depth(iter) const; + + /// Erase all nodes of the tree. + void clear(); + /// Erase element at position pointed to by iterator, return incremented iterator. + template iter erase(iter); + /// Erase all children of the node pointed to by iterator. + void erase_children(const iterator_base&); + + /// Insert empty node as last/first child of node pointed to by position. + template iter append_child(iter position); + template iter prepend_child(iter position); + /// Insert node as last/first child of node pointed to by position. + template iter append_child(iter position, const T& x); + template iter prepend_child(iter position, const T& x); + /// Append the node (plus its children) at other_position as last/first child of position. + template iter append_child(iter position, iter other_position); + template iter prepend_child(iter position, iter other_position); + /// Append the nodes in the from-to range (plus their children) as last/first children of position. + template iter append_children(iter position, sibling_iterator from, sibling_iterator to); + template iter prepend_children(iter position, sibling_iterator from, sibling_iterator to); + + /// Short-hand to insert topmost node in otherwise empty tree. + pre_order_iterator set_head(const T& x); + /// Insert node as previous sibling of node pointed to by position. + template iter insert(iter position, const T& x); + /// Specialisation of previous member. + sibling_iterator insert(sibling_iterator position, const T& x); + /// Insert node (with children) pointed to by subtree as previous sibling of node pointed to by position. + template iter insert_subtree(iter position, const iterator_base& subtree); + /// Insert node as next sibling of node pointed to by position. + template iter insert_after(iter position, const T& x); + /// Insert node (with children) pointed to by subtree as next sibling of node pointed to by position. + template iter insert_subtree_after(iter position, const iterator_base& subtree); + + /// Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. + template iter replace(iter position, const T& x); + /// Replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above. + template iter replace(iter position, const iterator_base& from); + /// Replace string of siblings (plus their children) with copy of a new string (with children); see above + sibling_iterator replace(sibling_iterator orig_begin, sibling_iterator orig_end, + sibling_iterator new_begin, sibling_iterator new_end); + + /// Move all children of node at 'position' to be siblings, returns position. + template iter flatten(iter position); + /// Move nodes in range to be children of 'position'. + template iter reparent(iter position, sibling_iterator begin, sibling_iterator end); + /// Move all child nodes of 'from' to be children of 'position'. + template iter reparent(iter position, iter from); + + /// Replace node with a new node, making the old node a child of the new node. + template iter wrap(iter position, const T& x); + + /// Move 'source' node (plus its children) to become the next sibling of 'target'. + template iter move_after(iter target, iter source); + /// Move 'source' node (plus its children) to become the previous sibling of 'target'. + template iter move_before(iter target, iter source); + sibling_iterator move_before(sibling_iterator target, sibling_iterator source); + /// Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target'). + template iter move_ontop(iter target, iter source); + + /// Merge with other tree, creating new branches and leaves only if they are not already present. + void merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, + bool duplicate_leaves=false); + /// Sort (std::sort only moves values of nodes, this one moves children as well). + void sort(sibling_iterator from, sibling_iterator to, bool deep=false); + template + void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); + /// Compare two ranges of nodes (compares nodes as well as tree structure). + template + bool equal(const iter& one, const iter& two, const iter& three) const; + template + bool equal(const iter& one, const iter& two, const iter& three, BinaryPredicate) const; + template + bool equal_subtree(const iter& one, const iter& two) const; + template + bool equal_subtree(const iter& one, const iter& two, BinaryPredicate) const; + /// Extract a new tree formed by the range of siblings plus all their children. + tree subtree(sibling_iterator from, sibling_iterator to) const; + void subtree(tree&, sibling_iterator from, sibling_iterator to) const; + /// Exchange the node (plus subtree) with its sibling node (do nothing if no sibling present). + void swap(sibling_iterator it); + /// Exchange two nodes (plus subtrees) + void swap(iterator, iterator); + + /// Count the total number of nodes. + size_t size() const; + /// Count the total number of nodes below the indicated node (plus one). + size_t size(const iterator_base&) const; + /// Check if tree is empty. + bool empty() const; + /// Compute the depth to the root or to a fixed other iterator. + static int depth(const iterator_base&); + static int depth(const iterator_base&, const iterator_base&); + /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. + int max_depth() const; + /// Determine the maximal depth of the tree with top node at the given position. + int max_depth(const iterator_base&) const; + /// Count the number of children of node at position. + static unsigned int number_of_children(const iterator_base&); + /// Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1. + unsigned int number_of_siblings(const iterator_base&) const; + /// Determine whether node at position is in the subtrees with root in the range. + bool is_in_subtree(const iterator_base& position, const iterator_base& begin, + const iterator_base& end) const; + /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. + bool is_valid(const iterator_base&) const; + /// Find the lowest common ancestor of two nodes, that is, the deepest node such that + /// both nodes are descendants of it. + iterator lowest_common_ancestor(const iterator_base&, const iterator_base &) const; + + /// Determine the index of a node in the range of siblings to which it belongs. + unsigned int index(sibling_iterator it) const; + /// Inverse of 'index': return the n-th child of the node at position. + static sibling_iterator child(const iterator_base& position, unsigned int); + /// Return iterator to the sibling indicated by index + sibling_iterator sibling(const iterator_base& position, unsigned int); + + /// For debugging only: verify internal consistency by inspecting all pointers in the tree + /// (which will also trigger a valgrind error in case something got corrupted). + void debug_verify_consistency() const; + + /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) + class iterator_base_less { + public: + bool operator()(const typename tree::iterator_base& one, + const typename tree::iterator_base& two) const + { + return one.node < two.node; + } + }; + tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid + private: + tree_node_allocator alloc_; + void head_initialise_(); + void copy_(const tree& other); + + /// Comparator class for two nodes of a tree (used for sorting and searching). + template + class compare_nodes { + public: + compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; + + bool operator()(const tree_node *a, const tree_node *b) + { + return comp_(a->data, b->data); + } + private: + StrictWeakOrdering comp_; + }; +}; + +//template +//class iterator_base_less { +// public: +// bool operator()(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) const +// { +// txtout << "operatorclass<" << one.node < two.node << std::endl; +// return one.node < two.node; +// } +//}; + +// template +// bool operator<(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator< " << one.node < two.node << std::endl; +// if(one.node < two.node) return true; +// return false; +// } +// +// template +// bool operator==(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator== " << one.node == two.node << std::endl; +// if(one.node == two.node) return true; +// return false; +// } +// +// template +// bool operator>(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) +// { +// txtout << "operator> " << one.node < two.node << std::endl; +// if(one.node > two.node) return true; +// return false; +// } + + + +// Tree + +template +tree::tree() + { + head_initialise_(); + } + +template +tree::tree(const T& x) + { + head_initialise_(); + set_head(x); + } + +template +tree::tree(const iterator_base& other) + { + head_initialise_(); + set_head((*other)); + replace(begin(), other); + } + +template +tree::~tree() + { + clear(); + alloc_.destroy(head); + alloc_.destroy(feet); + alloc_.deallocate(head,1); + alloc_.deallocate(feet,1); + } + +template +void tree::head_initialise_() + { + head = alloc_.allocate(1,0); // MSVC does not have default second argument + feet = alloc_.allocate(1,0); + alloc_.construct(head, tree_node_()); + alloc_.construct(feet, tree_node_()); + + head->parent=0; + head->first_child=0; + head->last_child=0; + head->prev_sibling=0; //head; + head->next_sibling=feet; //head; + + feet->parent=0; + feet->first_child=0; + feet->last_child=0; + feet->prev_sibling=head; + feet->next_sibling=0; + } + +template +tree& tree::operator=(const tree& other) + { + if(this != &other) + copy_(other); + return *this; + } + +template +tree::tree(const tree& other) + { + head_initialise_(); + copy_(other); + } + +template +void tree::copy_(const tree& other) + { + clear(); + pre_order_iterator it=other.begin(), to=begin(); + while(it!=other.end()) { + to=insert(to, (*it)); + it.skip_children(); + ++it; + } + to=begin(); + it=other.begin(); + while(it!=other.end()) { + to=replace(to, it); + to.skip_children(); + it.skip_children(); + ++to; + ++it; + } + } + +template +void tree::clear() + { + if(head) + while(head->next_sibling!=feet) + erase(pre_order_iterator(head->next_sibling)); + } + +template +void tree::erase_children(const iterator_base& it) + { +// std::cout << "erase_children " << it.node << std::endl; + if(it.node==0) return; + + tree_node *cur=it.node->first_child; + tree_node *prev=0; + + while(cur!=0) { + prev=cur; + cur=cur->next_sibling; + erase_children(pre_order_iterator(prev)); +// kp::destructor(&prev->data); + alloc_.destroy(prev); + alloc_.deallocate(prev,1); + } + it.node->first_child=0; + it.node->last_child=0; +// std::cout << "exit" << std::endl; + } + +template +template +iter tree::erase(iter it) + { + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ret.skip_children(); + ++ret; + erase_children(it); + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + +// kp::destructor(&cur->data); + alloc_.destroy(cur); + alloc_.deallocate(cur,1); + return ret; + } + +template +typename tree::pre_order_iterator tree::begin() const + { + return pre_order_iterator(head->next_sibling); + } + +template +typename tree::pre_order_iterator tree::end() const + { + return pre_order_iterator(feet); + } + +template +typename tree::breadth_first_queued_iterator tree::begin_breadth_first() const + { + return breadth_first_queued_iterator(head->next_sibling); + } + +template +typename tree::breadth_first_queued_iterator tree::end_breadth_first() const + { + return breadth_first_queued_iterator(); + } + +template +typename tree::post_order_iterator tree::begin_post() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return post_order_iterator(tmp); + } + +template +typename tree::post_order_iterator tree::end_post() const + { + return post_order_iterator(feet); + } + +template +typename tree::fixed_depth_iterator tree::begin_fixed(const iterator_base& pos, unsigned int dp) const + { + typename tree::fixed_depth_iterator ret; + ret.top_node=pos.node; + + tree_node *tmp=pos.node; + unsigned int curdepth=0; + while(curdepthfirst_child==0) { + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + if(tmp==ret.top_node) + throw std::range_error("tree: begin_fixed out of range"); + tmp=tmp->parent; + if(tmp==0) + throw std::range_error("tree: begin_fixed out of range"); + --curdepth; + } while(tmp->next_sibling==0); + } + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + } + + ret.node=tmp; + return ret; + } + +template +typename tree::fixed_depth_iterator tree::end_fixed(const iterator_base& pos, unsigned int dp) const + { + assert(1==0); // FIXME: not correct yet: use is_valid() as a temporary workaround + tree_node *tmp=pos.node; + unsigned int curdepth=1; + while(curdepthfirst_child==0) { + tmp=tmp->next_sibling; + if(tmp==0) + throw std::range_error("tree: end_fixed out of range"); + } + tmp=tmp->first_child; + ++curdepth; + } + return tmp; + } + +template +typename tree::sibling_iterator tree::begin(const iterator_base& pos) const + { + assert(pos.node!=0); + if(pos.node->first_child==0) { + return end(pos); + } + return pos.node->first_child; + } + +template +typename tree::sibling_iterator tree::end(const iterator_base& pos) const + { + sibling_iterator ret(0); + ret.parent_=pos.node; + return ret; + } + +template +typename tree::leaf_iterator tree::begin_leaf() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return leaf_iterator(tmp); + } + +template +typename tree::leaf_iterator tree::end_leaf() const + { + return leaf_iterator(feet); + } + +template +typename tree::leaf_iterator tree::begin_leaf(const iterator_base& top) const + { + tree_node *tmp=top.node; + while(tmp->first_child) + tmp=tmp->first_child; + return leaf_iterator(tmp, top.node); + } + +template +typename tree::leaf_iterator tree::end_leaf(const iterator_base& top) const + { + return leaf_iterator(top.node, top.node); + } + +template +template +iter tree::parent(iter position) + { + assert(position.node!=0); + return iter(position.node->parent); + } + +template +template +iter tree::previous_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->prev_sibling; + return ret; + } + +template +template +iter tree::next_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->next_sibling; + return ret; + } + +template +template +iter tree::next_at_same_depth(iter position) const + { + // We make use of a temporary fixed_depth iterator to implement this. + + typename tree::fixed_depth_iterator tmp(position.node); + + ++tmp; + return iter(tmp); + +// assert(position.node!=0); +// iter ret(position); +// +// if(position.node->next_sibling) { +// ret.node=position.node->next_sibling; +// } +// else { +// int relative_depth=0; +// upper: +// do { +// ret.node=ret.node->parent; +// if(ret.node==0) return ret; +// --relative_depth; +// } while(ret.node->next_sibling==0); +// lower: +// ret.node=ret.node->next_sibling; +// while(ret.node->first_child==0) { +// if(ret.node->next_sibling==0) +// goto upper; +// ret.node=ret.node->next_sibling; +// if(ret.node==0) return ret; +// } +// while(relative_depth<0 && ret.node->first_child!=0) { +// ret.node=ret.node->first_child; +// ++relative_depth; +// } +// if(relative_depth<0) { +// if(ret.node->next_sibling==0) goto upper; +// else goto lower; +// } +// } +// return ret; + } + +template +template +iter tree::append_child(iter position) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + alloc_.construct(tmp, tree_node_()); +// kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + alloc_.construct(tmp, tree_node_()); +// kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->prev_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, const T& x) + { + // If your program fails here you probably used 'append_child' to add the top + // node to an empty tree. From version 1.45 the top element should be added + // using 'insert'. See the documentation for further information, and sorry about + // the API change. + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position, const T& x) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->first_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + sibling_iterator aargh=append_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::prepend_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + sibling_iterator aargh=prepend_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::append_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.end(), from); + ++from; + } + return ret; + } + +template +template +iter tree::prepend_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.begin(), from); + ++from; + } + return ret; + } + +template +typename tree::pre_order_iterator tree::set_head(const T& x) + { + assert(head->next_sibling==feet); + return insert(iterator(feet), x); + } + +template +template +iter tree::insert(iter position, const T& x) + { + if(position.node==0) { + position.node=feet; // Backward compatibility: when calling insert on a null node, + // insert before the feet. + } + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->next_sibling=position.node; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +typename tree::sibling_iterator tree::insert(sibling_iterator position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->next_sibling=position.node; + if(position.node==0) { // iterator points to end of a subtree + tmp->parent=position.parent_; + tmp->prev_sibling=position.range_last(); + tmp->parent->last_child=tmp; + } + else { + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + } + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +template +iter tree::insert_after(iter position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node; + tmp->next_sibling=position.node->next_sibling; + position.node->next_sibling=tmp; + + if(tmp->next_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->last_child=tmp; + } + else { + tmp->next_sibling->prev_sibling=tmp; + } + return tmp; + } + +template +template +iter tree::insert_subtree(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +template +template +iter tree::insert_subtree_after(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert_after(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +// template +// template +// iter tree::insert_subtree(sibling_iterator position, iter subtree) +// { +// // insert dummy +// iter it(insert(position, value_type())); +// // replace dummy with subtree +// return replace(it, subtree); +// } + +template +template +iter tree::replace(iter position, const T& x) + { +// kp::destructor(&position.node->data); +// kp::constructor(&position.node->data, x); + position.node->data=x; +// alloc_.destroy(position.node); +// alloc_.construct(position.node, x); + return position; + } + +template +template +iter tree::replace(iter position, const iterator_base& from) + { + assert(position.node!=head); + tree_node *current_from=from.node; + tree_node *start_from=from.node; + tree_node *current_to =position.node; + + // replace the node at position with head of the replacement tree at from +// std::cout << "warning!" << position.node << std::endl; + erase_children(position); +// std::cout << "no warning!" << std::endl; + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, (*from)); +// kp::constructor(&tmp->data, (*from)); + tmp->first_child=0; + tmp->last_child=0; + if(current_to->prev_sibling==0) { + if(current_to->parent!=0) + current_to->parent->first_child=tmp; + } + else { + current_to->prev_sibling->next_sibling=tmp; + } + tmp->prev_sibling=current_to->prev_sibling; + if(current_to->next_sibling==0) { + if(current_to->parent!=0) + current_to->parent->last_child=tmp; + } + else { + current_to->next_sibling->prev_sibling=tmp; + } + tmp->next_sibling=current_to->next_sibling; + tmp->parent=current_to->parent; +// kp::destructor(¤t_to->data); + alloc_.destroy(current_to); + alloc_.deallocate(current_to,1); + current_to=tmp; + + // only at this stage can we fix 'last' + tree_node *last=from.node->next_sibling; + + pre_order_iterator toit=tmp; + // copy all children + do { + assert(current_from!=0); + if(current_from->first_child != 0) { + current_from=current_from->first_child; + toit=append_child(toit, current_from->data); + } + else { + while(current_from->next_sibling==0 && current_from!=start_from) { + current_from=current_from->parent; + toit=parent(toit); + assert(current_from!=0); + } + current_from=current_from->next_sibling; + if(current_from!=last) { + toit=append_child(parent(toit), current_from->data); + } + } + } while(current_from!=last); + + return current_to; + } + +template +typename tree::sibling_iterator tree::replace( + sibling_iterator orig_begin, + sibling_iterator orig_end, + sibling_iterator new_begin, + sibling_iterator new_end) + { + tree_node *orig_first=orig_begin.node; + tree_node *new_first=new_begin.node; + tree_node *orig_last=orig_first; + while((++orig_begin)!=orig_end) + orig_last=orig_last->next_sibling; + tree_node *new_last=new_first; + while((++new_begin)!=new_end) + new_last=new_last->next_sibling; + + // insert all siblings in new_first..new_last before orig_first + bool first=true; + pre_order_iterator ret; + while(1==1) { + pre_order_iterator tt=insert_subtree(pre_order_iterator(orig_first), pre_order_iterator(new_first)); + if(first) { + ret=tt; + first=false; + } + if(new_first==new_last) + break; + new_first=new_first->next_sibling; + } + + // erase old range of siblings + bool last=false; + tree_node *next=orig_first; + while(1==1) { + if(next==orig_last) + last=true; + next=next->next_sibling; + erase((pre_order_iterator)orig_first); + if(last) + break; + orig_first=next; + } + return ret; + } + +template +template +iter tree::flatten(iter position) + { + if(position.node->first_child==0) + return position; + + tree_node *tmp=position.node->first_child; + while(tmp) { + tmp->parent=position.node->parent; + tmp=tmp->next_sibling; + } + if(position.node->next_sibling) { + position.node->last_child->next_sibling=position.node->next_sibling; + position.node->next_sibling->prev_sibling=position.node->last_child; + } + else { + position.node->parent->last_child=position.node->last_child; + } + position.node->next_sibling=position.node->first_child; + position.node->next_sibling->prev_sibling=position.node; + position.node->first_child=0; + position.node->last_child=0; + + return position; + } + + +template +template +iter tree::reparent(iter position, sibling_iterator begin, sibling_iterator end) + { + tree_node *first=begin.node; + tree_node *last=first; + + assert(first!=position.node); + + if(begin==end) return begin; + // determine last node + while((++begin)!=end) { + last=last->next_sibling; + } + // move subtree + if(first->prev_sibling==0) { + first->parent->first_child=last->next_sibling; + } + else { + first->prev_sibling->next_sibling=last->next_sibling; + } + if(last->next_sibling==0) { + last->parent->last_child=first->prev_sibling; + } + else { + last->next_sibling->prev_sibling=first->prev_sibling; + } + if(position.node->first_child==0) { + position.node->first_child=first; + position.node->last_child=last; + first->prev_sibling=0; + } + else { + position.node->last_child->next_sibling=first; + first->prev_sibling=position.node->last_child; + position.node->last_child=last; + } + last->next_sibling=0; + + tree_node *pos=first; + for(;;) { + pos->parent=position.node; + if(pos==last) break; + pos=pos->next_sibling; + } + + return first; + } + +template +template iter tree::reparent(iter position, iter from) + { + if(from.node->first_child==0) return position; + return reparent(position, from.node->first_child, end(from)); + } + +template +template iter tree::wrap(iter position, const T& x) + { + assert(position.node!=0); + sibling_iterator fr=position, to=position; + ++to; + iter ret = insert(position, x); + reparent(ret, fr, to); + return ret; + } + +template +template iter tree::move_after(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->next_sibling) + if(dst->next_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; + else dst->parent->last_child=src; + src->next_sibling=dst->next_sibling; + dst->next_sibling=src; + src->prev_sibling=dst; + src->parent=dst->parent; + return src; + } + +template +template iter tree::move_before(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->prev_sibling) + if(dst->prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; + else dst->parent->first_child=src; + src->prev_sibling=dst->prev_sibling; + dst->prev_sibling=src; + src->next_sibling=dst; + src->parent=dst->parent; + return src; + } + +// specialisation for sibling_iterators +template +typename tree::sibling_iterator tree::move_before(sibling_iterator target, + sibling_iterator source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + tree_node *dst_prev_sibling; + if(dst==0) { // must then be an end iterator + dst_prev_sibling=target.parent_->last_child; + assert(dst_prev_sibling); + } + else dst_prev_sibling=dst->prev_sibling; + assert(src); + + if(dst==src) return source; + if(dst_prev_sibling) + if(dst_prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst_prev_sibling!=0) dst_prev_sibling->next_sibling=src; + else target.parent_->first_child=src; + src->prev_sibling=dst_prev_sibling; + if(dst) { + dst->prev_sibling=src; + src->parent=dst->parent; + } + src->next_sibling=dst; + return src; + } + +template +template iter tree::move_ontop(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + +// if(dst==src->prev_sibling) { +// +// } + + // remember connection points + tree_node *b_prev_sibling=dst->prev_sibling; + tree_node *b_next_sibling=dst->next_sibling; + tree_node *b_parent=dst->parent; + + // remove target + erase(target); + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(b_prev_sibling!=0) b_prev_sibling->next_sibling=src; + else b_parent->first_child=src; + if(b_next_sibling!=0) b_next_sibling->prev_sibling=src; + else b_parent->last_child=src; + src->prev_sibling=b_prev_sibling; + src->next_sibling=b_next_sibling; + src->parent=b_parent; + return src; + } + +template +void tree::merge(sibling_iterator to1, sibling_iterator to2, + sibling_iterator from1, sibling_iterator from2, + bool duplicate_leaves) + { + sibling_iterator fnd; + while(from1!=from2) { + if((fnd=std::find(to1, to2, (*from1))) != to2) { // element found + if(from1.begin()==from1.end()) { // full depth reached + if(duplicate_leaves) + append_child(parent(to1), (*from1)); + } + else { // descend further + merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(), duplicate_leaves); + } + } + else { // element missing + insert_subtree(to2, from1); + } + ++from1; + } + } + + +template +void tree::sort(sibling_iterator from, sibling_iterator to, bool deep) + { + std::less comp; + sort(from, to, comp, deep); + } + +template +template +void tree::sort(sibling_iterator from, sibling_iterator to, + StrictWeakOrdering comp, bool deep) + { + if(from==to) return; + // make list of sorted nodes + // CHECK: if multiset stores equivalent nodes in the order in which they + // are inserted, then this routine should be called 'stable_sort'. + std::multiset > nodes(comp); + sibling_iterator it=from, it2=to; + while(it != to) { + nodes.insert(it.node); + ++it; + } + // reassemble + --it2; + + // prev and next are the nodes before and after the sorted range + tree_node *prev=from.node->prev_sibling; + tree_node *next=it2.node->next_sibling; + typename std::multiset >::iterator nit=nodes.begin(), eit=nodes.end(); + if(prev==0) { + if((*nit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*nit)->parent->first_child=(*nit); + } + else prev->next_sibling=(*nit); + + --eit; + while(nit!=eit) { + (*nit)->prev_sibling=prev; + if(prev) + prev->next_sibling=(*nit); + prev=(*nit); + ++nit; + } + // prev now points to the last-but-one node in the sorted range + if(prev) + prev->next_sibling=(*eit); + + // eit points to the last node in the sorted range. + (*eit)->next_sibling=next; + (*eit)->prev_sibling=prev; // missed in the loop above + if(next==0) { + if((*eit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*eit)->parent->last_child=(*eit); + } + else next->prev_sibling=(*eit); + + if(deep) { // sort the children of each node too + sibling_iterator bcs(*nodes.begin()); + sibling_iterator ecs(*eit); + ++ecs; + while(bcs!=ecs) { + sort(begin(bcs), end(bcs), comp, deep); + ++bcs; + } + } + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_) const + { + std::equal_to comp; + return equal(one_, two, three_, comp); + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_) const + { + std::equal_to comp; + return equal_subtree(one_, two_, comp); + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), three(three_); + +// if(one==two && is_valid(three) && three.number_of_children()!=0) +// return false; + while(one!=two && is_valid(three)) { + if(!fun(*one,*three)) + return false; + if(one.number_of_children()!=three.number_of_children()) + return false; + ++one; + ++three; + } + return true; + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), two(two_); + + if(!fun(*one,*two)) return false; + if(number_of_children(one)!=number_of_children(two)) return false; + return equal(begin(one),end(one),begin(two),fun); + } + +template +tree tree::subtree(sibling_iterator from, sibling_iterator to) const + { + tree tmp; + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + return tmp; + } + +template +void tree::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const + { + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + } + +template +size_t tree::size() const + { + size_t i=0; + pre_order_iterator it=begin(), eit=end(); + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +size_t tree::size(const iterator_base& top) const + { + size_t i=0; + pre_order_iterator it=top, eit=top; + eit.skip_children(); + ++eit; + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +bool tree::empty() const + { + pre_order_iterator it=begin(), eit=end(); + return (it==eit); + } + +template +int tree::depth(const iterator_base& it) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::depth(const iterator_base& it, const iterator_base& root) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0 && pos!=root.node) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::max_depth() const + { + int maxd=-1; + for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) + maxd=std::max(maxd, max_depth(it)); + + return maxd; + } + + +template +int tree::max_depth(const iterator_base& pos) const + { + tree_node *tmp=pos.node; + + if(tmp==0 || tmp==head || tmp==feet) return -1; + + int curdepth=0, maxdepth=0; + while(true) { // try to walk the bottom of the tree + while(tmp->first_child==0) { + if(tmp==pos.node) return maxdepth; + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + tmp=tmp->parent; + if(tmp==0) return maxdepth; + --curdepth; + } while(tmp->next_sibling==0); + } + if(tmp==pos.node) return maxdepth; + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + maxdepth=std::max(curdepth, maxdepth); + } + } + +template +unsigned int tree::number_of_children(const iterator_base& it) + { + tree_node *pos=it.node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; +// while(pos!=it.node->last_child) { +// ++ret; +// pos=pos->next_sibling; +// } + while((pos=pos->next_sibling)) + ++ret; + return ret; + } + +template +unsigned int tree::number_of_siblings(const iterator_base& it) const + { + tree_node *pos=it.node; + unsigned int ret=0; + // count forward + while(pos->next_sibling && + pos->next_sibling!=head && + pos->next_sibling!=feet) { + ++ret; + pos=pos->next_sibling; + } + // count backward + pos=it.node; + while(pos->prev_sibling && + pos->prev_sibling!=head && + pos->prev_sibling!=feet) { + ++ret; + pos=pos->prev_sibling; + } + + return ret; + } + +template +void tree::swap(sibling_iterator it) + { + tree_node *nxt=it.node->next_sibling; + if(nxt) { + if(it.node->prev_sibling) + it.node->prev_sibling->next_sibling=nxt; + else + it.node->parent->first_child=nxt; + nxt->prev_sibling=it.node->prev_sibling; + tree_node *nxtnxt=nxt->next_sibling; + if(nxtnxt) + nxtnxt->prev_sibling=it.node; + else + it.node->parent->last_child=it.node; + nxt->next_sibling=it.node; + it.node->prev_sibling=nxt; + it.node->next_sibling=nxtnxt; + } + } + +template +void tree::swap(iterator one, iterator two) + { + // if one and two are adjacent siblings, use the sibling swap + if(one.node->next_sibling==two.node) swap(one); + else if(two.node->next_sibling==one.node) swap(two); + else { + tree_node *nxt1=one.node->next_sibling; + tree_node *nxt2=two.node->next_sibling; + tree_node *pre1=one.node->prev_sibling; + tree_node *pre2=two.node->prev_sibling; + tree_node *par1=one.node->parent; + tree_node *par2=two.node->parent; + + // reconnect + one.node->parent=par2; + one.node->next_sibling=nxt2; + if(nxt2) nxt2->prev_sibling=one.node; + else par2->last_child=one.node; + one.node->prev_sibling=pre2; + if(pre2) pre2->next_sibling=one.node; + else par2->first_child=one.node; + + two.node->parent=par1; + two.node->next_sibling=nxt1; + if(nxt1) nxt1->prev_sibling=two.node; + else par1->last_child=two.node; + two.node->prev_sibling=pre1; + if(pre1) pre1->next_sibling=two.node; + else par1->first_child=two.node; + } + } + +// template +// tree::iterator tree::find_subtree( +// sibling_iterator subfrom, sibling_iterator subto, iterator from, iterator to, +// BinaryPredicate fun) const +// { +// assert(1==0); // this routine is not finished yet. +// while(from!=to) { +// if(fun(*subfrom, *from)) { +// +// } +// } +// return to; +// } + +template +bool tree::is_in_subtree(const iterator_base& it, const iterator_base& begin, + const iterator_base& end) const + { + // FIXME: this should be optimised. + pre_order_iterator tmp=begin; + while(tmp!=end) { + if(tmp==it) return true; + ++tmp; + } + return false; + } + +template +bool tree::is_valid(const iterator_base& it) const + { + if(it.node==0 || it.node==feet || it.node==head) return false; + else return true; + } + +template +typename tree::iterator tree::lowest_common_ancestor( + const iterator_base& one, const iterator_base& two) const + { + std::set parents; + + // Walk up from 'one' storing all parents. + iterator walk=one; + do { + walk=parent(walk); + parents.insert(walk); + } while( is_valid(parent(walk)) ); + + // Walk up from 'two' until we encounter a node in parents. + walk=two; + do { + walk=parent(walk); + if(parents.find(walk) != parents.end()) break; + } while( is_valid(parent(walk)) ); + + return walk; + } + +template +unsigned int tree::index(sibling_iterator it) const + { + unsigned int ind=0; + if(it.node->parent==0) { + while(it.node->prev_sibling!=head) { + it.node=it.node->prev_sibling; + ++ind; + } + } + else { + while(it.node->prev_sibling!=0) { + it.node=it.node->prev_sibling; + ++ind; + } + } + return ind; + } + +template +typename tree::sibling_iterator tree::sibling(const iterator_base& it, unsigned int num) + { + tree_node *tmp; + if(it.node->parent==0) { + tmp=head->next_sibling; + while(num) { + tmp = tmp->next_sibling; + --num; + } + } + else { + tmp=it.node->parent->first_child; + while(num) { + assert(tmp!=0); + tmp = tmp->next_sibling; + --num; + } + } + return tmp; + } + +template +void tree::debug_verify_consistency() const + { + iterator it=begin(); + while(it!=end()) { + if(it.node->parent!=0) { + if(it.node->prev_sibling==0) + assert(it.node->parent->first_child==it.node); + else + assert(it.node->prev_sibling->next_sibling==it.node); + if(it.node->next_sibling==0) + assert(it.node->parent->last_child==it.node); + else + assert(it.node->next_sibling->prev_sibling==it.node); + } + ++it; + } + } + +template +typename tree::sibling_iterator tree::child(const iterator_base& it, unsigned int num) + { + tree_node *tmp=it.node->first_child; + while(num--) { + assert(tmp!=0); + tmp=tmp->next_sibling; + } + return tmp; + } + + + + +// Iterator base + +template +tree::iterator_base::iterator_base() + : node(0), skip_current_children_(false) + { + } + +template +tree::iterator_base::iterator_base(tree_node *tn) + : node(tn), skip_current_children_(false) + { + } + +template +T& tree::iterator_base::operator*() const + { + return node->data; + } + +template +T* tree::iterator_base::operator->() const + { + return &(node->data); + } + +template +bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::post_order_iterator::operator==(const post_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator!=(const sibling_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator==(const sibling_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator==(const leaf_iterator& other) const + { + if(other.node==this->node && other.top_node==this->top_node) return true; + else return false; + } + +template +typename tree::sibling_iterator tree::iterator_base::begin() const + { + if(node->first_child==0) + return end(); + + sibling_iterator ret(node->first_child); + ret.parent_=this->node; + return ret; + } + +template +typename tree::sibling_iterator tree::iterator_base::end() const + { + sibling_iterator ret(0); + ret.parent_=node; + return ret; + } + +template +void tree::iterator_base::skip_children() + { + skip_current_children_=true; + } + +template +void tree::iterator_base::skip_children(bool skip) + { + skip_current_children_=skip; + } + +template +unsigned int tree::iterator_base::number_of_children() const + { + tree_node *pos=node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + while(pos!=node->last_child) { + ++ret; + pos=pos->next_sibling; + } + return ret; + } + + + +// Pre-order iterator + +template +tree::pre_order_iterator::pre_order_iterator() + : iterator_base(0) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() + { + assert(this->node!=0); + if(!this->skip_current_children_ && this->node->first_child != 0) { + this->node=this->node->first_child; + } + else { + this->skip_current_children_=false; + while(this->node->next_sibling==0) { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + this->node=this->node->next_sibling; + } + return *this; + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() + { + assert(this->node!=0); + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + } + else { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + return *this; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) + { + pre_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) +{ + pre_order_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + + + +// Post-order iterator + +template +tree::post_order_iterator::post_order_iterator() + : iterator_base(0) + { + } + +template +tree::post_order_iterator::post_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::post_order_iterator::post_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::post_order_iterator::post_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator++() + { + assert(this->node!=0); + if(this->node->next_sibling==0) { + this->node=this->node->parent; + this->skip_current_children_=false; + } + else { + this->node=this->node->next_sibling; + if(this->skip_current_children_) { + this->skip_current_children_=false; + } + else { + while(this->node->first_child) + this->node=this->node->first_child; + } + } + return *this; + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator--() + { + assert(this->node!=0); + if(this->skip_current_children_ || this->node->last_child==0) { + this->skip_current_children_=false; + while(this->node->prev_sibling==0) + this->node=this->node->parent; + this->node=this->node->prev_sibling; + } + else { + this->node=this->node->last_child; + } + return *this; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator++(int) + { + post_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator--(int) + { + post_order_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +void tree::post_order_iterator::descend_all() + { + assert(this->node!=0); + while(this->node->first_child) + this->node=this->node->first_child; + } + + +// Breadth-first iterator + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator() + : iterator_base() + { + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) + : iterator_base(tn) + { + traversal_queue.push(tn); + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(const iterator_base& other) + : iterator_base(other.node) + { + traversal_queue.push(other.node); + } + +template +bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() + { + assert(this->node!=0); + + // Add child nodes and pop current node + sibling_iterator sib=this->begin(); + while(sib!=this->end()) { + traversal_queue.push(sib.node); + ++sib; + } + traversal_queue.pop(); + if(traversal_queue.size()>0) + this->node=traversal_queue.front(); + else + this->node=0; + return (*this); + } + +template +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) + { + breadth_first_queued_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + + + +// Fixed depth iterator + +template +tree::fixed_depth_iterator::fixed_depth_iterator() + : iterator_base() + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(tree_node *tn) + : iterator_base(tn), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const iterator_base& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const fixed_depth_iterator& other) + : iterator_base(other.node), top_node(other.top_node) + { + } + +template +bool tree::fixed_depth_iterator::operator==(const fixed_depth_iterator& other) const + { + if(other.node==this->node && other.top_node==top_node) return true; + else return false; + } + +template +bool tree::fixed_depth_iterator::operator!=(const fixed_depth_iterator& other) const + { + if(other.node!=this->node || other.top_node!=top_node) return true; + else return false; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator++() + { + assert(this->node!=0); + + if(this->node->next_sibling) { + this->node=this->node->next_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; // FIXME: return a proper fixed_depth end iterator once implemented + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->next_sibling==0); + lower: + this->node=this->node->next_sibling; + while(this->node->first_child==0) { + if(this->node->next_sibling==0) + goto upper; + this->node=this->node->next_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->first_child!=0) { + this->node=this->node->first_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->next_sibling==0) goto upper; + else goto lower; + } + } + return *this; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator--() + { + assert(this->node!=0); + + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->prev_sibling==0); + lower: + this->node=this->node->prev_sibling; + while(this->node->last_child==0) { + if(this->node->prev_sibling==0) + goto upper; + this->node=this->node->prev_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->last_child!=0) { + this->node=this->node->last_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->prev_sibling==0) goto upper; + else goto lower; + } + } + return *this; + +// +// +// assert(this->node!=0); +// if(this->node->prev_sibling!=0) { +// this->node=this->node->prev_sibling; +// assert(this->node!=0); +// if(this->node->parent==0 && this->node->prev_sibling==0) // head element +// this->node=0; +// } +// else { +// tree_node *par=this->node->parent; +// do { +// par=par->prev_sibling; +// if(par==0) { // FIXME: need to keep track of this! +// this->node=0; +// return *this; +// } +// } while(par->last_child==0); +// this->node=par->last_child; +// } +// return *this; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator++(int) + { + fixed_depth_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator--(int) + { + fixed_depth_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --(num); + } + return (*this); + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --(num); + } + return *this; + } + + +// Sibling iterator + +template +tree::sibling_iterator::sibling_iterator() + : iterator_base() + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(tree_node *tn) + : iterator_base(tn) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const iterator_base& other) + : iterator_base(other.node) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const sibling_iterator& other) + : iterator_base(other), parent_(other.parent_) + { + } + +template +void tree::sibling_iterator::set_parent_() + { + parent_=0; + if(this->node==0) return; + if(this->node->parent!=0) + parent_=this->node->parent; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator++() + { + if(this->node) + this->node=this->node->next_sibling; + return *this; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator--() + { + if(this->node) this->node=this->node->prev_sibling; + else { + assert(parent_); + this->node=parent_->last_child; + } + return *this; +} + +template +typename tree::sibling_iterator tree::sibling_iterator::operator++(int) + { + sibling_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::sibling_iterator tree::sibling_iterator::operator--(int) + { + sibling_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +typename tree::tree_node *tree::sibling_iterator::range_first() const + { + tree_node *tmp=parent_->first_child; + return tmp; + } + +template +typename tree::tree_node *tree::sibling_iterator::range_last() const + { + return parent_->last_child; + } + +// Leaf iterator + +template +tree::leaf_iterator::leaf_iterator() + : iterator_base(0), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) + : iterator_base(tn), top_node(top) + { + } + +template +tree::leaf_iterator::leaf_iterator(const iterator_base &other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + ++(*this); + } + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator++() + { + assert(this->node!=0); + if(this->node->first_child!=0) { // current node is no longer leaf (children got added) + while(this->node->first_child) + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node != 0 && this->node==top_node) return *this; + } + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator--() + { + assert(this->node!=0); + while (this->node->prev_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node !=0 && this->node==top_node) return *this; + } + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + return *this; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator++(int) + { + leaf_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator--(int) + { + leaf_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +#endif + +// Local variables: +// default-tab-width: 3 +// End: diff --git a/lib/tree-2.81/src/tree_example.cc b/lib/tree-2.81/src/tree_example.cc new file mode 100644 index 0000000..d351f51 --- /dev/null +++ b/lib/tree-2.81/src/tree_example.cc @@ -0,0 +1,59 @@ +/* + + Cadabra: a field-theory motivated computer algebra system. + Copyright (C) 2001-2009 Kasper Peeters + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include +#include +#include +#include "tree.hh" + +using namespace std; + +int main(int, char **) + { + tree tr; + tree::iterator top, one, two, loc, banana; + + top=tr.begin(); + one=tr.insert(top, "one"); + two=tr.append_child(one, "two"); + tr.append_child(two, "apple"); + banana=tr.append_child(two, "banana"); + tr.append_child(banana,"cherry"); + tr.append_child(two, "peach"); + tr.append_child(one,"three"); + + loc=find(tr.begin(), tr.end(), "two"); + if(loc!=tr.end()) { + tree::sibling_iterator sib=tr.begin(loc); + while(sib!=tr.end(loc)) { + cout << (*sib) << endl; + ++sib; + } + cout << endl; + tree::iterator sib2=tr.begin(loc); + tree::iterator end2=tr.end(loc); + while(sib2!=end2) { + for(int i=0; i + + (At the moment this only contains a printing utility, thanks to Linda + Buisman ) + + This program is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef tree_util_hh_ +#define tree_util_hh_ + +#include +#include "tree.hh" + +namespace kptree { + +template +void print_tree_bracketed(const tree& t, std::ostream& str=std::cout); + +template +void print_subtree_bracketed(const tree& t, typename tree::iterator iRoot, + std::ostream& str=std::cout); + + + +// Iterate over all roots (the head) and print each one on a new line +// by calling printSingleRoot. + +template +void print_tree_bracketed(const tree& t, std::ostream& str) + { + int headCount = t.number_of_siblings(t.begin()); + int headNum = 0; + for(typename tree::sibling_iterator iRoots = t.begin(); iRoots != t.end(); ++iRoots, ++headNum) { + print_subtree_bracketed(t,iRoots,str); + if (headNum != headCount) { + str << std::endl; + } + } + } + + +// Print everything under this root in a flat, bracketed structure. + +template +void print_subtree_bracketed(const tree& t, typename tree::iterator iRoot, std::ostream& str) + { + if(t.empty()) return; + if (t.number_of_children(iRoot) == 0) { + str << *iRoot; + } + else { + // parent + str << *iRoot; + str << "("; + // child1, ..., childn + int siblingCount = t.number_of_siblings(t.begin(iRoot)); + int siblingNum; + typename tree::sibling_iterator iChildren; + for (iChildren = t.begin(iRoot), siblingNum = 0; iChildren != t.end(iRoot); ++iChildren, ++siblingNum) { + // recursively print child + print_subtree_bracketed(t,iChildren,str); + // comma after every child except the last one + if (siblingNum != siblingCount ) { + str << ", "; + } + } + str << ")"; + } + } + +} + +#endif diff --git a/lib/tree-2.81/src/xinlin.hh b/lib/tree-2.81/src/xinlin.hh new file mode 100644 index 0000000..f8db036 --- /dev/null +++ b/lib/tree-2.81/src/xinlin.hh @@ -0,0 +1,1579 @@ +// STL-like templated tree class. +// Revised by: Xinlin Cao(xinlincao@gmail.com) +// Revised from Kasper Peeters's implementation.(http://www.aei.mpg.de/~peekas/tree/) +// +//# removed sibling iterator +//# added children iterator +//# removed a lot of member functions from tree and iterators +//# changed set_head() to set_root() +//# added root() member function +//# added reparent_roo() member function +//# changed implementation of operator = () +//# changed some member functions about getting iterators +//# tested all member functions +//# removed implicit conversion between different iterators +//# removed depth iterator +// This version of tree is simpler than old one. It is robust and easy for using and understanding. +// Copyright (C) 2001-2009 Kasper Peeters +// Distributed under the GNU General Public License version 3, +// (eventually to be changed to the Boost Software License). + +/** \mainpage tree.hh +\author Kasper Peeters +\version 2.65 +\date 03-Apr-2009 +\see http://www.aei.mpg.de/~peekas/tree/ +\see http://www.aei.mpg.de/~peekas/tree/ChangeLog + +The tree.hh library for C++ provides an STL-like container class +for n-ary trees, templated over the data stored at the +nodes. Various types of iterators are provided (post-order, +pre-order, and others). Where possible the access methods are +compatible with the STL or alternative algorithms are +available. +*/ + +#ifndef tree_hh_ +#define tree_hh_ + +#include +#include +#include +#include +#include +#include +#include + +// HP-style construct/destroy have gone from the standard, +// so here is a copy. + +namespace kp { + + template + void constructor(T1* p, T2& val) + { + new ((void *) p) T1(val); + } + + template + void constructor(T1* p) + { + new ((void *) p) T1; + } + + template + void destructor(T1* p) + { + p->~T1(); + } + +} + +/// A node in the tree, combining links to other nodes as well as the actual data. +template +class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. +public: + tree_node_ *parent; + tree_node_ *first_child, *last_child; + tree_node_ *prev_sibling, *next_sibling; + T data; +}; // __attribute__((packed)); + +template > > +class tree { +protected: + typedef tree_node_ tree_node; +public: + /// Value of the data stored at a node. + typedef T value_type; + + class iterator_base; + class pre_order_iterator; + class post_order_iterator; + class children_iterator; + class leaf_iterator; + + tree(); + tree(const T&); + tree(const tree&); + ~tree(); + tree& operator=(const tree&); + + /// Base class for iterators, only pointers stored, no traversal logic. +#ifdef __SGI_STL_PORT + class iterator_base : public stlport::bidirectional_iterator { +#else + class iterator_base { +#endif + public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator_base(); + iterator_base(tree_node *); + + T& operator*() const; + T* operator->() const; + + /// Number of children of the node pointed to by the iterator. + unsigned int number_of_children() const; + + children_iterator begin_children_iterator() const; + children_iterator end_children_iterator() const; + + tree_node *node; + }; + + /// Depth-first iterator, first accessing the node, then its children. + class pre_order_iterator : public iterator_base { + public: + pre_order_iterator(); + pre_order_iterator(tree_node *); + + bool operator==(const pre_order_iterator&) const; + bool operator!=(const pre_order_iterator&) const; + pre_order_iterator& operator++(); + pre_order_iterator& operator--(); + pre_order_iterator operator++(int); + pre_order_iterator operator--(int); + pre_order_iterator& operator+=(unsigned int); + pre_order_iterator& operator-=(unsigned int); + }; + + /// Depth-first iterator, first accessing the children, then the node itself. + class post_order_iterator : public iterator_base { + public: + post_order_iterator(); + post_order_iterator(tree_node *); + + bool operator==(const post_order_iterator&) const; + bool operator!=(const post_order_iterator&) const; + post_order_iterator& operator++(); + post_order_iterator& operator--(); + post_order_iterator operator++(int); + post_order_iterator operator--(int); + post_order_iterator& operator+=(unsigned int); + post_order_iterator& operator-=(unsigned int); + + /// Set iterator to the first child as deep as possible down the tree. + void descend_all(); + }; + + /// Breadth-first iterator, using a queue + class breadth_first_queued_iterator : public iterator_base { + public: + breadth_first_queued_iterator(); + breadth_first_queued_iterator(tree_node *); + + bool operator==(const breadth_first_queued_iterator&) const; + bool operator!=(const breadth_first_queued_iterator&) const; + breadth_first_queued_iterator& operator++(); + breadth_first_queued_iterator operator++(int); + breadth_first_queued_iterator& operator+=(unsigned int); + + private: + std::queue traversal_queue; + }; + + /// Iterator which traverses only the nodes which are siblings of each other. + class children_iterator : public iterator_base { + public: + children_iterator(); + children_iterator(tree_node *); + + bool operator==(const children_iterator&) const; + bool operator!=(const children_iterator&) const; + children_iterator& operator++(); + children_iterator& operator--(); + children_iterator operator++(int); + children_iterator operator--(int); + children_iterator& operator+=(unsigned int); + children_iterator& operator-=(unsigned int); + + tree_node *range_first() const; + tree_node *range_last() const; + tree_node *parent_; + private: + void set_parent_(); + }; + + /// Iterator which traverses only the leaves. + class leaf_iterator : public iterator_base { + public: + leaf_iterator(); + leaf_iterator(tree_node *, tree_node *top=0); + + bool operator==(const leaf_iterator&) const; + bool operator!=(const leaf_iterator&) const; + leaf_iterator& operator++(); + leaf_iterator& operator--(); + leaf_iterator operator++(int); + leaf_iterator operator--(int); + leaf_iterator& operator+=(unsigned int); + leaf_iterator& operator-=(unsigned int); + private: + tree_node *top_node; + }; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator root() const; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator begin_pre_order_iterator(const iterator_base&) const; + /// Return iterator to the end of the tree. + inline pre_order_iterator end_pre_order_iterator(const iterator_base&) const; + /// Return post-order iterator to the beginning of the tree. + post_order_iterator begin_post_order_iterator(const iterator_base&) const; + /// Return post-order end iterator of the tree. + post_order_iterator end_post_order_iterator(const iterator_base&) const; + + + /// Return breadth-first iterator based on a iterator. + breadth_first_queued_iterator begin_breadth_first_iterator(const iterator_base&) const; + /// Return breadth-first end iterator. + breadth_first_queued_iterator end_breadth_first_iterator(const iterator_base&) const; + + + /// Return children iterator to the first child of given node. + children_iterator begin_children_iterator(const iterator_base&) const; + /// Return children end iterator for children of given node. + children_iterator end_children_iterator(const iterator_base&) const; + + /// Return leaf iterator to the first leaf of the subtree at the given node. + leaf_iterator begin_leaf_iterator(const iterator_base& top) const; + /// Return leaf end iterator for the subtree at the given node. + leaf_iterator end_leaf_iterator(const iterator_base& top) const; + + /// Return iterator to the parent of a node. + template static iter parent(iter); + /// Return iterator to the previous sibling of a node. + template iter previous_sibling(iter) const; + /// Return iterator to the next sibling of a node. + template iter next_sibling(iter) const; + + /// Erase all nodes of the tree. + void clear(); + /// Erase element at position pointed to by iterator, return incremented iterator. + template iter erase(iter); + /// Erase all children of the node pointed to by iterator. + void erase_children(const iterator_base&); + + + /// Short-hand to insert_before topmost node in otherwise empty tree. + pre_order_iterator set_root(const T& x); + + /// Insert node as last/first child of node pointed to by position. + template iter append_child(iter position, const T& x); + template iter prepend_child(iter position, const T& x); + + /// Insert node as previous sibling of node pointed to by position. + template iter insert_before(iter position, const T& x); + /// Insert node as next sibling of node pointed to by position. + template iter insert_after(iter position, const T& x); + + /// Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. + template iter replace(iter position, const T& x); + /// Replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above. + template iter replace(iter position, const iterator_base& from); + + ///set X as the new head of the tree, the old head will be a child of new head. + pre_order_iterator reparent_root(const T& x); + + /// Move 'source' node (plus its children) to become the next sibling of 'target'. + template iter move_after(iter target, iter source); + /// Move 'source' node (plus its children) to become the previous sibling of 'target'. + template iter move_before(iter target, iter source); + + /// Count the total number of nodes. + size_t size() const; + /// Count the total number of nodes below the indicated node (plus one). + size_t size(const iterator_base&) const; + /// Check if tree is empty. + bool empty() const; + /// Compute the depth to the root or to a fixed other iterator. + static int depth(const iterator_base&); + static int depth(const iterator_base&, const iterator_base&); + /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. + int max_depth() const; + /// Determine the maximal depth of the tree with top node at the given position. + int max_depth(const iterator_base&) const; + /// Count the number of children of node at position. + static unsigned int number_of_children(const iterator_base&); + /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. + bool is_valid(const iterator_base&) const; + + /// Determine the index of a node in the range of siblings to which it belongs. + unsigned int index(children_iterator it) const; + /// Inverse of 'index': return the n-th child of the node at position. + static children_iterator child(const iterator_base& position, unsigned int); + + /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) + class iterator_base_less { + public: + bool operator()(const typename tree::iterator_base& one, + const typename tree::iterator_base& two) const + { + return one.node < two.node; + } + }; + tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid +private: + tree_node_allocator alloc_; + void head_initialise_(); + void copy_(const tree& other); + + /// Comparator class for two nodes of a tree (used for sorting and searching). + template + class compare_nodes { + public: + compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; + + bool operator()(const tree_node *a, const tree_node *b) + { + return comp_(a->data, b->data); + } + private: + StrictWeakOrdering comp_; + }; +}; + + + +// Tree + +template +tree::tree() +{ + head_initialise_(); +} + +template +tree::tree(const T& x) +{ + head_initialise_(); + set_root(x); +} + +template +tree::~tree() +{ + clear(); + alloc_.deallocate(head,1); + alloc_.deallocate(feet,1); +} + +template +void tree::head_initialise_() +{ + head = alloc_.allocate(1,0); // MSVC does not have default second argument + feet = alloc_.allocate(1,0); + + head->parent=0; + head->first_child=0; + head->last_child=0; + head->prev_sibling=0; //head; + head->next_sibling=feet; //head; + + feet->parent=0; + feet->first_child=0; + feet->last_child=0; + feet->prev_sibling=head; + feet->next_sibling=0; +} + +template +tree& tree::operator=(const tree& other) +{ + if (this != &other) + { + copy_(other); + } + return (*this); +} + +template +tree::tree(const tree& other) +{ + head_initialise_(); + copy_(other); +} + +template +void tree::copy_(const tree& other) +{ + //check self + if (this == &other) + { + return; + } + clear(); + pre_order_iterator it=other.begin_pre_order_iterator(other.root()), to=begin_pre_order_iterator(root()); + while(it!=other.end_pre_order_iterator(other.root())) { + to=insert_before(to, (*it)); + ++it; + } + to=begin_pre_order_iterator(root()); + it=other.begin_pre_order_iterator(other.root()); + while(it!=other.end_pre_order_iterator(other.root())) { + to=replace(to, it); + ++to; + ++it; + } +} + +template +void tree::clear() +{ + if(head) + while(head->next_sibling!=feet) + erase(pre_order_iterator(head->next_sibling)); +} + +template +void tree::erase_children(const iterator_base& it) +{ + // std::cout << "erase_children " << it.node << std::endl; + if(it.node==0) return; + + tree_node *cur=it.node->first_child; + tree_node *prev=0; + + while(cur!=0) { + prev=cur; + cur=cur->next_sibling; + erase_children(pre_order_iterator(prev)); + kp::destructor(&prev->data); + alloc_.deallocate(prev,1); + } + it.node->first_child=0; + it.node->last_child=0; + // std::cout << "exit" << std::endl; +} + +template +template +iter tree::erase(iter it) +{ + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ++ret; + erase_children(it); + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + + kp::destructor(&cur->data); + alloc_.deallocate(cur,1); + return ret; +} + +template +typename tree::pre_order_iterator tree::root() const +{ + return pre_order_iterator(head->next_sibling); +} + + +template +typename tree::pre_order_iterator tree::begin_pre_order_iterator(const iterator_base& pos) const +{ + return pre_order_iterator(pos.node); +} + +template +typename tree::pre_order_iterator tree::end_pre_order_iterator(const iterator_base& pos) const +{ + return pre_order_iterator(pos.node->next_sibling); +} + + + +template +typename tree::breadth_first_queued_iterator tree::begin_breadth_first_iterator(const iterator_base& pos) const +{ + return breadth_first_queued_iterator(pos.node); +} + +template +typename tree::breadth_first_queued_iterator tree::end_breadth_first_iterator(const iterator_base& pos) const +{ + return breadth_first_queued_iterator(); +} + + +template +typename tree::post_order_iterator tree::begin_post_order_iterator(const iterator_base& pos) const +{ + tree_node *tmp=pos.node; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return post_order_iterator(tmp); +} + +template +typename tree::post_order_iterator tree::end_post_order_iterator(const iterator_base& pos) const +{ + return post_order_iterator(pos.node->next_sibling); +} + + +template +typename tree::children_iterator tree::begin_children_iterator(const iterator_base& pos) const +{ + assert(pos.node!=0); + if(pos.node->first_child==0) { + return end_children_iterator(pos); + } + return pos.node->first_child; +} + +template +typename tree::children_iterator tree::end_children_iterator(const iterator_base& pos) const +{ + children_iterator ret(0); + ret.parent_=pos.node; + return ret; +} + +template +typename tree::leaf_iterator tree::begin_leaf_iterator(const iterator_base& top) const +{ + tree_node *tmp=top.node; + while(tmp->first_child) + tmp=tmp->first_child; + return leaf_iterator(tmp, top.node); +} + +template +typename tree::leaf_iterator tree::end_leaf_iterator(const iterator_base& top) const +{ + return leaf_iterator(top.node, top.node); +} + +template +template +iter tree::parent(iter position) +{ + assert(position.node!=0); + return iter(position.node->parent); +} + +template +template +iter tree::previous_sibling(iter position) const +{ + assert(position.node!=0); + iter ret(position); + ret.node=position.node->prev_sibling; + return ret; +} + +template +template +iter tree::next_sibling(iter position) const +{ + assert(position.node!=0); + iter ret(position); + ret.node=position.node->next_sibling; + return ret; +} + +template +template +iter tree::append_child(iter position, const T& x) +{ + // If your program fails here you probably used 'append_child' to add the top + // node to an empty tree. From version 1.45 the top element should be added + // using 'insert_before'. See the documentation for further information, and sorry about + // the API change. + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; +} + +template +template +iter tree::prepend_child(iter position, const T& x) +{ + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->first_child=tmp; + tmp->prev_sibling=0; + return tmp; +} + + +template +typename tree::pre_order_iterator tree::set_root(const T& x) +{ + assert(head->next_sibling==feet); + return insert_before(pre_order_iterator(feet), x); +} + +template +template +iter tree::insert_before(iter position, const T& x) +{ + if(position.node==0) { + position.node=feet; // Backward compatibility: when calling insert_before on a null node, + // insert_before before the feet. + } + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->next_sibling=position.node; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; +} + + +template +template +iter tree::insert_after(iter position, const T& x) +{ + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node; + tmp->next_sibling=position.node->next_sibling; + position.node->next_sibling=tmp; + + if(tmp->next_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->last_child=tmp; + } + else { + tmp->next_sibling->prev_sibling=tmp; + } + return tmp; +} + + +template +template +iter tree::replace(iter position, const T& x) +{ + kp::destructor(&position.node->data); + kp::constructor(&position.node->data, x); + return position; +} + +template +template +iter tree::replace(iter position, const iterator_base& from) +{ + assert(position.node!=head); + tree_node *current_from=from.node; + tree_node *start_from=from.node; + tree_node *current_to =position.node; + + // replace the node at position with head of the replacement tree at from + // std::cout << "warning!" << position.node << std::endl; + erase_children(position); + // std::cout << "no warning!" << std::endl; + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, (*from)); + tmp->first_child=0; + tmp->last_child=0; + if(current_to->prev_sibling==0) { + if(current_to->parent!=0) + current_to->parent->first_child=tmp; + } + else { + current_to->prev_sibling->next_sibling=tmp; + } + tmp->prev_sibling=current_to->prev_sibling; + if(current_to->next_sibling==0) { + if(current_to->parent!=0) + current_to->parent->last_child=tmp; + } + else { + current_to->next_sibling->prev_sibling=tmp; + } + tmp->next_sibling=current_to->next_sibling; + tmp->parent=current_to->parent; + kp::destructor(¤t_to->data); + alloc_.deallocate(current_to,1); + current_to=tmp; + + // only at this stage can we fix 'last' + tree_node *last=from.node->next_sibling; + + pre_order_iterator toit=tmp; + // copy all children + do { + assert(current_from!=0); + if(current_from->first_child != 0) { + current_from=current_from->first_child; + toit=append_child(toit, current_from->data); + } + else { + while(current_from->next_sibling==0 && current_from!=start_from) { + current_from=current_from->parent; + toit=parent(toit); + assert(current_from!=0); + } + current_from=current_from->next_sibling; + if(current_from!=last) { + toit=append_child(parent(toit), current_from->data); + } + } + } while(current_from!=last); + + return current_to; +} + + +///set X as the new head of the tree, the old head will be a child of new head. +template +typename tree::pre_order_iterator tree::reparent_root(const T& x) +{ + if(head->next_sibling == feet->prev_sibling) + { + return this->set_root(x); + } + else + { + //remember the old head + tree_node *old_head_node = head->next_sibling; + + //create a new head + insert_before(pre_order_iterator(feet), x); + + //change the tree head + tree_node *new_head_node = head->next_sibling->next_sibling; + head->next_sibling = new_head_node; + + //change the new head + new_head_node->first_child = old_head_node; + new_head_node->last_child = old_head_node; + new_head_node->next_sibling = feet; + new_head_node->prev_sibling = head; + + //change the feet + feet->prev_sibling = new_head_node; + + //change the old head + old_head_node->next_sibling = 0; + old_head_node->prev_sibling = 0; + old_head_node->parent = new_head_node; + + return begin_pre_order_iterator(root()); + } +} + +template +template iter tree::move_after(iter target, iter source) +{ + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->next_sibling) + if(dst->next_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; + else dst->parent->last_child=src; + src->next_sibling=dst->next_sibling; + dst->next_sibling=src; + src->prev_sibling=dst; + src->parent=dst->parent; + return src; +} + +template +template iter tree::move_before(iter target, iter source) +{ + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->prev_sibling) + if(dst->prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; + else dst->parent->first_child=src; + src->prev_sibling=dst->prev_sibling; + dst->prev_sibling=src; + src->next_sibling=dst; + src->parent=dst->parent; + return src; +} + + +template +size_t tree::size() const +{ + size_t i=0; + pre_order_iterator it=begin_pre_order_iterator(), eit=end_pre_order_iterator(); + while(it!=eit) { + ++i; + ++it; + } + return i; +} + +template +size_t tree::size(const iterator_base& top) const +{ + size_t i=0; + pre_order_iterator it=top, eit=top; + ++eit; + while(it!=eit) { + ++i; + ++it; + } + return i; +} + +template +bool tree::empty() const +{ + pre_order_iterator it=begin_pre_order_iterator(), eit=end_pre_order_iterator(); + return (it==eit); +} + +template +int tree::depth(const iterator_base& it) +{ + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0) { + pos=pos->parent; + ++ret; + } + return ret; +} + +template +int tree::depth(const iterator_base& it, const iterator_base& root) +{ + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0 && pos!=root.node) { + pos=pos->parent; + ++ret; + } + return ret; +} + +template +int tree::max_depth() const +{ + int maxd=-1; + for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) + maxd=std::max(maxd, max_depth(it)); + + return maxd; +} + + +template +int tree::max_depth(const iterator_base& pos) const +{ + tree_node *tmp=pos.node; + + if(tmp==0 || tmp==head || tmp==feet) return -1; + + int curdepth=0, maxdepth=0; + while(true) { // try to walk the bottom of the tree + while(tmp->first_child==0) { + if(tmp==pos.node) return maxdepth; + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + tmp=tmp->parent; + if(tmp==0) return maxdepth; + --curdepth; + } while(tmp->next_sibling==0); + } + if(tmp==pos.node) return maxdepth; + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + maxdepth=std::max(curdepth, maxdepth); + } +} + +template +unsigned int tree::number_of_children(const iterator_base& it) +{ + tree_node *pos=it.node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + // while(pos!=it.node->last_child) { + // ++ret; + // pos=pos->next_sibling; + // } + while((pos=pos->next_sibling)) + ++ret; + return ret; +} + +template +bool tree::is_valid(const iterator_base& it) const +{ + if(it.node==0 || it.node==feet || it.node==head) return false; + else return true; +} + +template +unsigned int tree::index(children_iterator it) const +{ + unsigned int ind=0; + if(it.node->parent==0) { + while(it.node->prev_sibling!=head) { + it.node=it.node->prev_sibling; + ++ind; + } + } + else { + while(it.node->prev_sibling!=0) { + it.node=it.node->prev_sibling; + ++ind; + } + } + return ind; +} + +template +typename tree::children_iterator tree::child(const iterator_base& it, unsigned int num) +{ + tree_node *tmp=it.node->first_child; + while(num--) { + assert(tmp!=0); + tmp=tmp->next_sibling; + } + return tmp; +} + + + + +// Iterator base + +template +tree::iterator_base::iterator_base() +: node(0) +{ +} + +template +tree::iterator_base::iterator_base(tree_node *tn) +: node(tn) +{ +} + +template +T& tree::iterator_base::operator*() const +{ + return node->data; +} + +template +T* tree::iterator_base::operator->() const +{ + return &(node->data); +} + +template +bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::post_order_iterator::operator==(const post_order_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +bool tree::children_iterator::operator!=(const children_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::children_iterator::operator==(const children_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::leaf_iterator::operator==(const leaf_iterator& other) const +{ + if(other.node==this->node && other.top_node==this->top_node) return true; + else return false; +} + +template +typename tree::children_iterator tree::iterator_base::begin_children_iterator() const +{ + if(node->first_child==0) + return end_children_iterator(); + + children_iterator ret(node->first_child); + ret.parent_=this->node; + return ret; +} + +template +typename tree::children_iterator tree::iterator_base::end_children_iterator() const +{ + children_iterator ret(0); + ret.parent_=node; + return ret; +} + +template +unsigned int tree::iterator_base::number_of_children() const +{ + tree_node *pos=node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + while(pos!=node->last_child) { + ++ret; + pos=pos->next_sibling; + } + return ret; +} + + + +// Pre-order iterator + +template +tree::pre_order_iterator::pre_order_iterator() +: iterator_base(0) +{ +} + +template +tree::pre_order_iterator::pre_order_iterator(tree_node *tn) +: iterator_base(tn) +{ +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() +{ + assert(this->node!=0); + if(this->node->first_child != 0) { + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + this->node=this->node->next_sibling; + } + return *this; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() +{ + assert(this->node!=0); + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + } + else { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + return *this; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) +{ + pre_order_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) +{ + pre_order_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + + + +// Post-order iterator + +template +tree::post_order_iterator::post_order_iterator() +: iterator_base(0) +{ +} + +template +tree::post_order_iterator::post_order_iterator(tree_node *tn) +: iterator_base(tn) +{ +} + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator++() +{ + assert(this->node!=0); + if(this->node->next_sibling==0) { + this->node=this->node->parent; + } + else { + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; +} + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator--() +{ + assert(this->node!=0); + if(this->skip_current_children_ || this->node->last_child==0) { + this->skip_current_children_=false; + while(this->node->prev_sibling==0) + this->node=this->node->parent; + this->node=this->node->prev_sibling; + } + else { + this->node=this->node->last_child; + } + return *this; +} + +template +typename tree::post_order_iterator tree::post_order_iterator::operator++(int) +{ + post_order_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::post_order_iterator tree::post_order_iterator::operator--(int) +{ + post_order_iterator copy = *this; + --(*this); + return copy; +} + + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + +template +void tree::post_order_iterator::descend_all() +{ + assert(this->node!=0); + while(this->node->first_child) + this->node=this->node->first_child; +} + + +// Breadth-first iterator + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator() +: iterator_base() +{ +} + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) +: iterator_base(tn) +{ + traversal_queue.push(tn); +} + +template +bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const +{ + if(other.node!=this->node) return true; + else return false; +} + +template +bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const +{ + if(other.node==this->node) return true; + else return false; +} + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() +{ + assert(this->node!=0); + + // Add child nodes and pop current node + children_iterator sib=this->begin_children_iterator(); + while(sib!=this->end_children_iterator()) { + traversal_queue.push(sib.node); + ++sib; + } + traversal_queue.pop(); + if(traversal_queue.size()>0) + this->node=traversal_queue.front(); + else + this->node=0; + return (*this); +} + +template +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) +{ + breadth_first_queued_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +// Sibling iterator + +template +tree::children_iterator::children_iterator() +: iterator_base() +{ + set_parent_(); +} + +template +tree::children_iterator::children_iterator(tree_node *tn) +: iterator_base(tn) +{ + set_parent_(); +} + +template +void tree::children_iterator::set_parent_() +{ + parent_=0; + if(this->node==0) return; + if(this->node->parent!=0) + parent_=this->node->parent; +} + +template +typename tree::children_iterator& tree::children_iterator::operator++() +{ + if(this->node) + this->node=this->node->next_sibling; + return *this; +} + +template +typename tree::children_iterator& tree::children_iterator::operator--() +{ + if(this->node) this->node=this->node->prev_sibling; + else { + assert(parent_); + this->node=parent_->last_child; + } + return *this; +} + +template +typename tree::children_iterator tree::children_iterator::operator++(int) +{ + children_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::children_iterator tree::children_iterator::operator--(int) +{ + children_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::children_iterator& tree::children_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::children_iterator& tree::children_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + +template +typename tree::tree_node *tree::children_iterator::range_first() const +{ + tree_node *tmp=parent_->first_child; + return tmp; +} + +template +typename tree::tree_node *tree::children_iterator::range_last() const +{ + return parent_->last_child; +} + +// Leaf iterator + +template +tree::leaf_iterator::leaf_iterator() +: iterator_base(0), top_node(0) +{ +} + +template +tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) +: iterator_base(tn), top_node(top) +{ +} + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator++() +{ + assert(this->node!=0); + if(this->node->first_child!=0) { // current node is no longer leaf (children got added) + while(this->node->first_child) + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node != 0 && this->node==top_node) return *this; + } + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; +} + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator--() +{ + assert(this->node!=0); + while (this->node->prev_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node !=0 && this->node==top_node) return *this; + } + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + return *this; +} + +template +typename tree::leaf_iterator tree::leaf_iterator::operator++(int) +{ + leaf_iterator copy = *this; + ++(*this); + return copy; +} + +template +typename tree::leaf_iterator tree::leaf_iterator::operator--(int) +{ + leaf_iterator copy = *this; + --(*this); + return copy; +} + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) +{ + while(num>0) { + ++(*this); + --num; + } + return (*this); +} + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) +{ + while(num>0) { + --(*this); + --num; + } + return (*this); +} + +#endif diff --git a/lib/vectorwrapper b/lib/vectorwrapper index 50ebba1..fc7b666 160000 --- a/lib/vectorwrapper +++ b/lib/vectorwrapper @@ -1 +1 @@ -Subproject commit 50ebba1c3157196d142bc06ebf2d290c7702b084 +Subproject commit fc7b66642959e7de19aade010b6ebc1e59ba4b7a diff --git a/nonfree_map.tmx b/nonfree_map.tmx index 386e532..3124404 100644 --- a/nonfree_map.tmx +++ b/nonfree_map.tmx @@ -2,456 +2,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gamelib/character.cpp b/src/character.cpp similarity index 59% rename from src/gamelib/character.cpp rename to src/character.cpp index 2e75122..971e4f9 100644 --- a/src/gamelib/character.cpp +++ b/src/character.cpp @@ -21,27 +21,58 @@ #include "inputbag.hpp" #include "gameactions.hpp" #include "worldgrid.hpp" -#include "drawing_queue.hpp" -#include "worldviewport.hpp" -#include "texture.hpp" -#include "draw_layer_names.hpp" #include #include -#include namespace curry { + namespace { + } //unnamed namespace + Character::Character (cloonel::InputBag* parInputBag, const WorldSizeNotifiable::DeferredRegister& parDeferredRegister) : - WorldMoveable(parDeferredRegister), + WorldSizeNotifiable(parDeferredRegister), + m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f)), + m_width_height(0.0f), m_input_bag(parInputBag), + m_world(parDeferredRegister.world()), m_speed(1.0f) { assert(m_input_bag); + assert(m_world); + } + + void Character::load (const char* parTexturePath, cloonel::SDLMain& parSDLMain) { + const auto old_wh = m_width_height; + m_texture.load(parTexturePath, parSDLMain); + m_width_height = vector_cast(m_texture.width_height()); + const auto& new_wh = m_width_height; + if (m_position.get_min() != m_position.get_max()) + m_position.change_minmax(m_position.get_min(), m_position.get_max() + old_wh - new_wh); + } + + void Character::unload() { + m_texture.unload(); + } + + void Character::set_position (const vec2f& parPos) { + m_position = parPos; + } + + const vec2f& Character::position() const { + return m_position.get(); + } + + const vec2f& Character::width_height() const { + return m_width_height; + } + + Texture& Character::texture() { + return m_texture; } Rect Character::destination_rect (const vec2f& parWorldPos) const { return Rect( - position() - parWorldPos, - position() - parWorldPos + width_height() + m_position.get() - parWorldPos, + m_position.get() - parWorldPos + width_height() ); } @@ -52,6 +83,10 @@ namespace curry { ); } + void Character::world_size_changed (const vec2us&, const vec2i& parPixelSize) { + m_position.change_minmax(m_position.get_min(), vector_cast(parPixelSize)); + } + void Character::do_movement (float parDeltaT) { const float speed = parDeltaT * m_speed; vec2f offset(0.0f); @@ -65,18 +100,10 @@ namespace curry { offset.y() += speed; const auto old_pos = this->position(); - this->set_position(old_pos + offset); - if (position() == old_pos) - return; + const auto new_pos = old_pos + offset; - WorldGrid& world = this->world(); + //if (m_world - const vec2f new_pos = m_collider.try_reach_tile( - texture()->width_height() / world.tile_size(), - old_pos, - position(), - world - ); this->set_position(new_pos); } @@ -84,17 +111,4 @@ namespace curry { assert(parSpeed > 0.0f); m_speed = parSpeed; } - - void Character::draw (DrawingQueue& parDQ, const WorldViewport& parViewport) { - DrawingQueue::ItemInfo item; - item.source = source_rect(); - item.destination = destination_rect(parViewport.position()); - item.texture = texture(); - parDQ.add_for_rendering(DrawaLayerNames::Characters, std::move(item)); - assert(not item.texture); - } - - void Character::on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz) { - this->update_moveable_size(parOldSz, parNewSz); - } } //namespace curry diff --git a/src/gamelib/character.hpp b/src/character.hpp similarity index 68% rename from src/gamelib/character.hpp rename to src/character.hpp index 796e62e..008410a 100644 --- a/src/gamelib/character.hpp +++ b/src/character.hpp @@ -19,11 +19,12 @@ #pragma once +#include "texture.hpp" #include "vector.hpp" #include "rect.hpp" -#include "world_moveable.hpp" -#include "drawable.hpp" -#include "collider.hpp" +#include "constrained_position.hpp" +#include "worldsizenotifiable.hpp" +#include "moveable.hpp" namespace cloonel { class SDLMain; @@ -33,22 +34,29 @@ namespace cloonel { namespace curry { class WorldGrid; - class Character : public Drawable, public WorldMoveable { + class Character : public WorldSizeNotifiable, public Moveable { public: Character (cloonel::InputBag* parInputBag, const WorldSizeNotifiable::DeferredRegister& parDeferredRegister); virtual ~Character() noexcept = default; + void load (const char* parTexturePath, cloonel::SDLMain& parSDLMain); + void unload(); + const vec2f& position() const; + void set_position (const vec2f& parPos); + const vec2f& width_height() const; + Texture& texture(); Rect destination_rect (const vec2f& parWorldPos) const; Rect source_rect() const; + virtual void world_size_changed (const vec2us& parSize, const vec2i& parPixelSize) override; virtual void do_movement (float parDeltaT) override; void set_speed (float parSpeed); - virtual void draw (DrawingQueue& parDQ, const WorldViewport& parViewport) override; private: - virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz) override; - + ConstrainedPosition m_position; + Texture m_texture; + vec2f m_width_height; cloonel::InputBag* m_input_bag; - Collider m_collider; + WorldGrid* m_world; float m_speed; }; } //namespace curry diff --git a/src/gamelib/compatibility.h b/src/compatibility.h similarity index 100% rename from src/gamelib/compatibility.h rename to src/compatibility.h diff --git a/src/gamelib/constrained_position.hpp b/src/constrained_position.hpp similarity index 100% rename from src/gamelib/constrained_position.hpp rename to src/constrained_position.hpp diff --git a/src/gamelib/constrained_value.hpp b/src/constrained_value.hpp similarity index 100% rename from src/gamelib/constrained_value.hpp rename to src/constrained_value.hpp diff --git a/src/coordinates.hpp b/src/coordinates.hpp new file mode 100644 index 0000000..d4d0b7a --- /dev/null +++ b/src/coordinates.hpp @@ -0,0 +1,53 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#pragma once + +#include "vector.hpp" +#include "singlecoordinate.hpp" + +namespace vwr { + template <> + struct VectorWrapperInfo> { + enum { dimensions = 2 }; + typedef ::curry::SingleCoordinate scalar_type; + typedef std::array vector_type; + static scalar_type& get_at (size_t parIndex, vector_type& parVector) { + return parVector[parIndex]; + } + }; +} //namespace vwr + +namespace curry { + using vec2c = vwr::Vec>; + + inline vec2i to_screen_coordinates (vec2c parVec, const vec2i& parWorldOffset, vec2us parTileSize) { + return vec2i( + parVec.x().screen_coordinate(parWorldOffset.x(), parTileSize.x()), + parVec.y().screen_coordinate(parWorldOffset.y(), parTileSize.y()) + ); + } + + inline vec2us to_tiles (vec2c parVec) { + return vec2us( + parVec.x().tile(), + parVec.y().tile() + ); + } +} //namespace curry diff --git a/src/gamelib/csvloader.cpp b/src/csvloader.cpp similarity index 81% rename from src/gamelib/csvloader.cpp rename to src/csvloader.cpp index c3c732f..ceb9a78 100644 --- a/src/gamelib/csvloader.cpp +++ b/src/csvloader.cpp @@ -35,7 +35,6 @@ #include #include #include -#include namespace qi = boost::spirit::qi; @@ -48,7 +47,6 @@ namespace curry { //auto csv_parser = *((qi::int_ % ',') >> -qi::eol) >> qi::eoi; CSVJointData out_csv; std::size_t row_count = 0; - TileIndex largest_tile_idx = 0; for (auto& csv_path : parCsvPath) { std::ifstream f_map(csv_path); @@ -68,9 +66,6 @@ namespace curry { oss << "Error parsing csv \"" << csv_path << "\""; throw std::runtime_error(oss.str()); } - if (not curr_data.empty()) { - largest_tile_idx = std::max(*std::max_element(curr_data.begin(), curr_data.end()), largest_tile_idx); - } out_csv.tables.emplace_back(std::move(curr_data)); } @@ -81,18 +76,6 @@ namespace curry { else { out_csv.height = out_csv.width = 0; } - - out_csv.tile_properties.resize(static_cast(largest_tile_idx) + 1); - out_csv.tile_properties[2].walkable = false; - -#if !defined(NDEBUG) - for (const auto& table : out_csv.tables) { - for (const auto& val : table) { - const auto casted_val = static_cast(val); - assert(val < 0 or casted_val < out_csv.tile_properties.size()); - } - } -#endif return out_csv; } } //namespace curry diff --git a/src/gamelib/csvloader.hpp b/src/csvloader.hpp similarity index 91% rename from src/gamelib/csvloader.hpp rename to src/csvloader.hpp index ce3672d..587e9cb 100644 --- a/src/gamelib/csvloader.hpp +++ b/src/csvloader.hpp @@ -20,7 +20,6 @@ #pragma once #include "tileindextype.hpp" -#include "tileproperty.hpp" #include #include #include @@ -32,7 +31,6 @@ namespace curry { CSVJointData (const CSVJointData&) = delete; std::vector> tables; - std::vector tile_properties; //not filled in with real values uint16_t width; uint16_t height; }; diff --git a/src/gamelib/gameactions.hpp b/src/gameactions.hpp similarity index 100% rename from src/gamelib/gameactions.hpp rename to src/gameactions.hpp diff --git a/src/gamelib/CMakeLists.txt b/src/gamelib/CMakeLists.txt deleted file mode 100644 index 140d7aa..0000000 --- a/src/gamelib/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -project(mycurry_gamelib CXX) - -PKG_SEARCH_MODULE(SDL2 REQUIRED IMPORTED_TARGET sdl2) -PKG_SEARCH_MODULE(SDL2IMAGE REQUIRED IMPORTED_TARGET SDL2_image>=2.0.0) -find_package(PNG REQUIRED) - -add_library(${PROJECT_NAME} - csvloader.cpp - ingamescene.cpp - gamescenebase.cpp - worldgrid.cpp - worldviewport.cpp - tileiterator.cpp - texture.cpp - movingobject.cpp - character.cpp - rect_to_sdl.cpp - worldsizenotifiable.cpp - worlditems.cpp - moveable.cpp - grid_raytrace.cpp - drawable.cpp - drawing_queue.cpp - world_moveable.cpp - collider.cpp -) -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14) -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) - -target_include_directories(${PROJECT_NAME} SYSTEM - PRIVATE ${PNG_INCLUDE_DIRS} - PRIVATE ${Boost_INCLUDE_DIRS} -) -target_include_directories(${PROJECT_NAME} - PUBLIC ${CMAKE_SOURCE_DIR}/lib/vectorwrapper/include - PRIVATE ${CMAKE_BINARY_DIR} -) - -target_link_libraries(${PROJECT_NAME} - PRIVATE PkgConfig::SDL2 - PRIVATE PkgConfig::SDL2IMAGE - PRIVATE ${PNG_LIBRARIES} - PUBLIC mycurry_toplevel - PUBLIC cloonelgraphics - PRIVATE tmxlite -) - -target_compile_definitions(${PROJECT_NAME} - PRIVATE ${PNG_DEFINITIONS} - PUBLIC VWR_WITH_IMPLICIT_CONVERSIONS=1 - PUBLIC VWR_EXTRA_ACCESSORS -) diff --git a/src/gamelib/collider.cpp b/src/gamelib/collider.cpp deleted file mode 100644 index 4cfd314..0000000 --- a/src/gamelib/collider.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - Copyright 2016-2018 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "collider.hpp" -#include "grid_raytrace.hpp" -#include "worldgrid.hpp" -#include "vectorwrapper/sequence_range.hpp" -#include - -namespace curry { - namespace { - vec2us collision_borders (const vec2us& parObjSize, const vec2f& parDirection) { - assert(parObjSize > 0); - const uint16_t horz_offs = (parDirection.x() > 0.0f ? static_cast(parObjSize.x() - 1) : 0); - const uint16_t vert_offs = (parDirection.y() > 0.0f ? static_cast(parObjSize.y() - 1) : 0); - return vec2us(horz_offs, vert_offs); - } - - vec2us check_tiles_count (const vec2us& parObjSize, const vec2f& parDirection) { - assert(parObjSize > 0); - const uint16_t horz = (parDirection.y() != 0.0f ? parObjSize.x() : 1); - const uint16_t vert = (parDirection.x() != 0.0f ? parObjSize.y() : 1); - return vec2us(horz, vert); - } - - vec2f direction_mask (const vec2f& parDirection) { - const auto horz = (parDirection.x() == 0.0f ? 0.0f : 1.0f); - const auto vert = (parDirection.y() == 0.0f ? 0.0f : 1.0f); - return vec2f(horz, vert); - } - - vec2f make_pixel_side_offset ( - const vec2us& parTileSize, - const vec2us& parSideOffset, - const vec2f& parDirection - ) { - const vec2f tile_size = vector_cast(parTileSize); - vec2f tile_start = tile_size * vector_cast(parSideOffset); - if (parDirection.x() > 0.0f) - tile_start.x() += tile_size.x() - 1.0f; - if (parDirection.y() > 0.0f) - tile_start.y() += tile_size.y() - 1.0f; - return tile_start; - } - } //unnamed namespace - - vec2f Collider::try_reach_tile ( - const vec2us& parObjectSize, - const vec2f& parFrom, - const vec2f& parTo, - const WorldGrid& parWorld - ) { - const vec2f direction = parTo - parFrom; - if (direction == 0.0f) - return parTo; - - const vec2us side_offset = collision_borders(parObjectSize, direction); - const vec2us length = check_tiles_count(parObjectSize, direction); - const vec2f pix_side_offset = - make_pixel_side_offset(parWorld.tile_size(), side_offset, direction); - const vec2f to = parTo + pix_side_offset; - const vec2f from = parFrom + pix_side_offset; - vec2us stop_at = pixel_to_world_tile(parWorld, from); - const vec2us dest_tile = pixel_to_world_tile(parWorld, to); - vec2f tile_relative_offs = to - world_tile_to_pixel(parWorld, dest_tile); - assert(tile_relative_offs < vector_cast(parWorld.tile_size())); - - vec2f collision_mask(0.0f); - auto forward_callback = [=,&parWorld,&stop_at,&tile_relative_offs,&collision_mask](vec2us tile) { - for (auto curr_pos : vwr::increasing_sequence_range(tile, tile + length)) { - const bool walkable = parWorld.tile_property(parWorld.tile(curr_pos)).walkable; - if (not walkable) { - collision_mask = direction_mask(direction); - tile_relative_offs *= (1.0f - collision_mask); - return false; - } - } - stop_at = tile; - return true; - }; - - for_each_cell_under_segment( - from, - to, - parObjectSize, - parWorld, - forward_callback, - false - ); - - return world_tile_to_pixel(parWorld, stop_at) + tile_relative_offs - pix_side_offset + collision_mask * direction_mask(pix_side_offset) * 31.0f; - } -} //namespace curry diff --git a/src/gamelib/collider.hpp b/src/gamelib/collider.hpp deleted file mode 100644 index d7d5814..0000000 --- a/src/gamelib/collider.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright 2016-2018 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "vector.hpp" -#include "rect.hpp" -#include - -namespace curry { - class WorldGrid; - - class Collider { - public: - Collider() = default; - ~Collider() = default; - - vec2f try_reach_tile ( - const vec2us& parObjectSize, - const vec2f& parFrom, - const vec2f& parTo, - const WorldGrid& parWorld - ); - - private: - }; -} //namespace curry diff --git a/src/gamelib/draw_layer_names.hpp b/src/gamelib/draw_layer_names.hpp deleted file mode 100644 index 0065075..0000000 --- a/src/gamelib/draw_layer_names.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "enum.h" -#include - -namespace curry { -#if !defined(NDEBUG) - BETTER_ENUM(DrawaLayerNames, uint16_t, - Background, - Debug, - Characters - ) -#else - BETTER_ENUM(DrawaLayerNames, uint16_t, - Background, - Characters - ) -#endif -} //namespace curry diff --git a/src/gamelib/drawable.cpp b/src/gamelib/drawable.cpp deleted file mode 100644 index 7032e3b..0000000 --- a/src/gamelib/drawable.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "drawable.hpp" -#include "texture.hpp" -#include "safe_stack_object.hpp" -#include -#include -#include -#include - -namespace curry { - namespace { - vec2f max_size (const vec2f& parA, const vec2f& parB) { - return vec2f( - std::max(parA.x(), parB.x()), - std::max(parA.y(), parB.y()) - ); - } - } //unnamed namespace - - Drawable::Drawable() : - m_width_height(0.0f) - { - } - - Drawable::~Drawable() noexcept = default; - - size_t Drawable::add_texture (const char* parTexturePath, cloonel::SDLMain& parSDLMain) { - SafeStackObject new_texture; - new_texture->load(parTexturePath, parSDLMain); - const auto retval = store_new_texture(std::move(new_texture)); - return retval; - } - - size_t Drawable::add_texture (const vec2f& parSize, cloonel::SDLMain& parSDLMain) { - assert(parSize > 0.0f); - SafeStackObject new_texture; - new_texture->load_empty(parSDLMain, static_cast(parSize)); - const auto retval = store_new_texture(std::move(new_texture)); - return retval; - } - - void Drawable::unload_textures() noexcept { - for (auto& tex : m_textures) { - tex->unload(); - } - m_textures.clear(); - } - - const vec2f& Drawable::width_height() const { - return m_width_height; - } - - Kakoune::SafePtr& Drawable::texture() { - assert(not m_textures.empty()); - auto& retval = m_textures[0]; - return retval; - } - - void Drawable::on_texture_size_changed (const vec2f&, const vec2f&) { - } - - size_t Drawable::store_new_texture (SafeStackObject&& parNewTexture) { - const auto old_wh = m_width_height; - m_width_height = max_size(vector_cast(parNewTexture->width_height()), old_wh); - const auto& new_wh = m_width_height; - if (new_wh != old_wh) - this->on_texture_size_changed(old_wh, new_wh); - - m_textures.push_back(std::move(parNewTexture)); - assert(m_textures.size() > 0); - return m_textures.size() - 1; - } -} //namespace curry diff --git a/src/gamelib/drawable.hpp b/src/gamelib/drawable.hpp deleted file mode 100644 index a312b02..0000000 --- a/src/gamelib/drawable.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "safe_ptr.hh" -#include "vector.hpp" -#include - -namespace cloonel { - class SDLMain; -} //namespace cloonel - -namespace curry { - template class SafeStackObject; - class Texture; - class DrawingQueue; - class WorldViewport; - - class Drawable { - public: - Drawable(); - virtual ~Drawable() noexcept; - - size_t add_texture (const char* parTexturePath, cloonel::SDLMain& parSDLMain); - size_t add_texture (const vec2f& parSize, cloonel::SDLMain& parSDLMain); - - void unload_textures() noexcept; - const vec2f& width_height() const; - Kakoune::SafePtr& texture(); - virtual void draw ( DrawingQueue& parDQ, const WorldViewport& parViewport ) = 0; - - private: - size_t store_new_texture (SafeStackObject&& parNewTexture); - virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz); - - std::vector> m_textures; - vec2f m_width_height; - }; -} //namespace curry diff --git a/src/gamelib/drawing_queue.hpp b/src/gamelib/drawing_queue.hpp deleted file mode 100644 index 32f5cf3..0000000 --- a/src/gamelib/drawing_queue.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "safe_ptr.hh" -#include "rect.hpp" -#include "sizenotifiable.hpp" -#include -#include - -namespace cloonel { - class SDLMain; -} //namespace cloonel - -namespace curry { - class Texture; - - class DrawingQueue : public cloonel::SizeNotifiable { - typedef cloonel::SizeNotifiable SizeNotifiableBase; - public: - struct ItemInfo; - - DrawingQueue (cloonel::SDLMain* parSDLMain, const cloonel::DeferredRegister& parDeferredRegister); - virtual ~DrawingQueue() noexcept; - - bool add_layer (uint16_t parName); - std::size_t default_layer_id() const; - void flush_to_renderer(); - void add_for_rendering (uint16_t parName, ItemInfo&& parItem); - - private: - void draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest); - virtual void OnResChanged ( const cloonel::SizeRatio& parSizeRatio ) override; - - struct LocalData; - - std::unique_ptr m_local_data; - }; - - struct DrawingQueue::ItemInfo { - ItemInfo(); - ItemInfo (ItemInfo&&); - ItemInfo (const ItemInfo&) = delete; - ~ItemInfo() noexcept; - - ItemInfo& operator= (ItemInfo&&); - ItemInfo& operator= (const ItemInfo&) = delete; - - Rect source; - Rect destination; - Kakoune::SafePtr texture; - }; -} //namespace curry diff --git a/src/gamelib/gamescenebase.cpp b/src/gamelib/gamescenebase.cpp deleted file mode 100644 index 7d01b2a..0000000 --- a/src/gamelib/gamescenebase.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "gamescenebase.hpp" -#include "inputbag.hpp" -#include "sdlmain.hpp" -#include "rect.hpp" -#include "drawing_queue.hpp" -#include -#include -#include -#include -#if !defined(NDEBUG) -# include "compatibility.h" -# include -#endif - -namespace curry { - namespace { - ///--------------------------------------------------------------------- - ///--------------------------------------------------------------------- - bool DoEvents (cloonel::InputBag& parInput, cloonel::SDLMain* parSdlMain) { - using cloonel::InputDevice_Keyboard; - using cloonel::ushort2; - - SDL_Event eve; - while (SDL_PollEvent(&eve)) { - switch (eve.type) { - case SDL_KEYDOWN: - //eve.key.keysym.sym - parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, true); - break; - - case SDL_KEYUP: - parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, false); - break; - - case SDL_QUIT: - return true; - - case SDL_WINDOWEVENT: - if (SDL_WINDOWEVENT_RESIZED == eve.window.event) { - parSdlMain->SetResolution(ushort2(static_cast(eve.window.data1), static_cast(eve.window.data2))); - } - else if (SDL_WINDOWEVENT_CLOSE == eve.window.event) { - return true; - } - break; - } - } - return false; - } - } //unnamed namespace - - GameSceneBase::GameSceneBase (cloonel::SDLMain* parSdlMain) : - m_time0(std::chrono::steady_clock::now()), - m_input(std::make_unique()), - m_drawing_queue(std::make_unique(parSdlMain, cloonel::DeferredRegister())), - m_sdlmain(parSdlMain), - m_screen_width(static_cast(m_sdlmain->WidthHeight().x())), - m_screen_height(static_cast(m_sdlmain->WidthHeight().y())), - m_wants_to_quit(false) - { - assert(m_sdlmain); - } - - GameSceneBase::~GameSceneBase() noexcept = default; - - void GameSceneBase::prepare() { - m_wants_to_quit = false; - this->on_prepare(); - - m_time0 = std::chrono::steady_clock::now(); - } - - void GameSceneBase::destroy() noexcept { - set_wants_to_quit(); - this->on_destroy(); - } - - bool GameSceneBase::wants_to_quit() const { - return m_wants_to_quit; - } - - void GameSceneBase::set_wants_to_quit() { - m_wants_to_quit = true; - } - - void GameSceneBase::exec() { - const auto time1 = std::chrono::steady_clock::now(); - - const bool quit = DoEvents(*m_input, m_sdlmain); - m_input->KeyStateUpdateFinished(); - if (quit) - set_wants_to_quit(); - - const float delta = std::chrono::duration(time1 - m_time0).count(); - m_time0 = time1; - this->on_update(delta); - m_drawing_queue->flush_to_renderer(); - SDL_RenderPresent(this->sdl_main()->GetRenderer()); - } - - cloonel::SDLMain* GameSceneBase::sdl_main() { - return m_sdlmain; - } - - cloonel::InputBag& GameSceneBase::input_bag() { - return *m_input; - } - - DrawingQueue& GameSceneBase::drawing_queue() { - return *m_drawing_queue; - } - - const DrawingQueue& GameSceneBase::drawing_queue() const { - return *m_drawing_queue; - } -} //namespace curry diff --git a/src/gamelib/grid_raytrace.cpp b/src/gamelib/grid_raytrace.cpp deleted file mode 100644 index 0fbee0e..0000000 --- a/src/gamelib/grid_raytrace.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "grid_raytrace.hpp" -#include "worldgrid.hpp" -#include "vectorwrapper/vectorops.hpp" -#include "tileproperty.hpp" -#include -#include -#include -#include -#include -#include -#include - -namespace curry { -#if !defined(BUILD_TESTING) - namespace { -#endif - float inv_length (const vec2f& parVec) { - return 1.0f / std::sqrt(parVec.x() * parVec.x() + parVec.y() * parVec.y()); - } - - vec2f abs (const vec2f& parVec) { - return vec2f(std::abs(parVec.x()), std::abs(parVec.y())); - } - - float segment_intersection (const vec2f& parA, const vec2f& parDirA, const vec2f& parB, const vec2f& parDirB) { - const auto& p = parA; - const auto& r = parDirA; - const auto& q = parB; - const auto& s = parDirB; - - const auto r_cross_s = cross(r, s); - if (std::abs(r_cross_s) <= FLT_EPSILON) { - if (std::abs(cross(q - p, r)) <= FLT_EPSILON) { - assert(std::abs(dot(r, r)) > FLT_EPSILON); - auto t0 = dot(q - p, r) / dot(r, r); - auto t1 = dot(q - p + s, r) / dot(r, r); - if (dot(s, r) < 0.0f) - std::swap(t0, t1); - assert(t0 <= t1); - if (0.0f <= t0) - return t0; - else if (t1 <= 1.0f) - return t1; - else - return INFINITY; - } - else { - return INFINITY; - } - } - - assert(not (std::abs(r_cross_s) <= FLT_EPSILON)); - const auto inv_r_cross_s = 1.0f / r_cross_s; - const auto t = cross(q - p, s) * inv_r_cross_s; - //const auto u = cross(q - p, r) * inv_r_cross_s; - - return t; - //if (0.0f <= t and t <= 1.0f and 0.0f <= u and u <= 1.0f) - //return t; - //else - //return INFINITY; - } - - vec2f frac (vec2f parVal) { - return parVal - vec2f(std::floor(parVal.x()), std::floor(parVal.y())); - } - - template int sgn (T val) { - return (T(0) < val) - (val < T(0)); - } -#if !defined(BUILD_TESTING) - } //unnamed namespace -#endif - - //see: - //http://stackoverflow.com/questions/24679963/precise-subpixel-line-drawing-algorithm-rasterization-algorithm - void for_each_cell_under_segment ( - const vec2f& parFrom, - const vec2f& parTo, - vec2us parObjSize, - const WorldGrid& parWorld, - std::function parFunc, - bool parInclFirst - ) { - const vec2f tile_size = vector_cast(parWorld.tile_size()); - //in this simplified case everything should be part of the world grid - assert(parFrom >= vec2f(0.0f)); - assert(parTo >= vec2f(0.0f)); - assert(parFrom / tile_size <= vector_cast(parWorld.world_size())); - assert(parTo / tile_size <= vector_cast(parWorld.world_size())); - - //float t = 0.0f; - const vec2f& u = parFrom; - const vec2f v = parTo - parFrom; - - const auto delta = tile_size / abs(v); - const auto fr = frac(u / tile_size); - assert(fr.x() >= 0.0f and fr.x() < 1.0f); - assert(fr.y() >= 0.0f and fr.y() < 1.0f); - - //see: - //http://stackoverflow.com/questions/12367071/how-do-i-initialize-the-t-variables-in-a-fast-voxel-traversal-algorithm-for-ray#12370474 - const vec2i step(sgn(v.x()), sgn(v.y())); - vec2f max; - if (step.x() > 0) - max.x() = delta.x() * (1.0f - fr.x()); - else if (step.x() < 0) - max.x() = delta.x() * fr.x(); - else - max.x() = FLT_MAX; - if (step.y() > 0) - max.y() = delta.y() * (1.0f - fr.y()); - else if (step.y() < 0) - max.y() = delta.y() * fr.y(); - else - max.y() = FLT_MAX; - - vec2us curr_tile = pixel_to_world_tile(parWorld, u); - const vec2us last_tile = pixel_to_world_tile(parWorld, parTo); - bool& do_callback = parInclFirst; - while ( - ((do_callback and parFunc(curr_tile)) or not do_callback) - and last_tile != curr_tile - ) { - do_callback = true; - if (max.x() < max.y()) { - assert(step.x()); - assert( - std::max(static_cast(curr_tile.x() + step.x()), last_tile.x()) - - std::min(static_cast(curr_tile.x() + step.x()), last_tile.x()) < - std::max(curr_tile.x(), last_tile.x()) - - std::min(curr_tile.x(), last_tile.x()) - ); - max.x() += delta.x(); - curr_tile.x() = static_cast(curr_tile.x() + step.x()); - } - else { - assert(step.y()); - assert( - std::max(static_cast(curr_tile.y() + step.y()), last_tile.y()) - - std::min(static_cast(curr_tile.y() + step.y()), last_tile.y()) < - std::max(curr_tile.y(), last_tile.y()) - - std::min(curr_tile.y(), last_tile.y()) - ); - max.y() += delta.y(); - curr_tile.y() = static_cast(curr_tile.y() + step.y()); - } - } - } -} //namespace curry diff --git a/src/gamelib/grid_raytrace.hpp b/src/gamelib/grid_raytrace.hpp deleted file mode 100644 index c264efa..0000000 --- a/src/gamelib/grid_raytrace.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "vector.hpp" -#include "mycurry_toplevelConfig.h" -#include - -namespace curry { - class WorldGrid; - -#if defined(BUILD_TESTING) - float segment_intersection (const vec2f& parA, const vec2f& parDirA, const vec2f& parB, const vec2f& parDirB); -#endif - - void for_each_cell_under_segment ( - const vec2f& parFrom, - const vec2f& parTo, - vec2us parObjSize, - const WorldGrid& parWorld, - std::function parFunc, - bool parInclFirst - ); -} //namespace curry diff --git a/src/gamelib/safe_stack_object.hpp b/src/gamelib/safe_stack_object.hpp deleted file mode 100644 index f9e0439..0000000 --- a/src/gamelib/safe_stack_object.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "safe_ptr.hh" -#include - -namespace curry { - template - class SafeStackObject { - public: - typedef Kakoune::SafePtr safe_ptr; - - SafeStackObject(); - SafeStackObject (SafeStackObject&& parOther); - SafeStackObject (const SafeStackObject& parOther) = delete; - ~SafeStackObject() noexcept = default; - - SafeStackObject& operator= (SafeStackObject&& parOther) = delete; - SafeStackObject& operator= (const SafeStackObject& parOther) = delete; - - operator Kakoune::SafePtr&(); - safe_ptr& operator*(); - safe_ptr& operator->(); - - private: - T m_obj; - safe_ptr m_obj_ptr; - }; - - template - SafeStackObject::SafeStackObject() : - m_obj(), - m_obj_ptr(&m_obj) - { - } - - template - SafeStackObject::SafeStackObject (SafeStackObject&& parOther) : - m_obj(std::move(parOther.m_obj)), - m_obj_ptr(&m_obj) - { - } - - //template - //SafeStackObject& SafeStackObject::operator= (SafeStackObject&& parOther) { - // m_obj = std::move(parOther.m_obj); - // m_obj_ptr = std::move(parOther.m_obj_ptr); - // m_ob - //} - - //template - //SafeStackObject& SafeStackObject::operator= (const SafeStackObject& parOther) { - //} - - template - SafeStackObject::operator Kakoune::SafePtr&() { - return m_obj_ptr; - } - - template - auto SafeStackObject::operator*() -> safe_ptr& { - return m_obj_ptr; - } - - template - auto SafeStackObject::operator->() -> safe_ptr& { - return m_obj_ptr; - } -} //namespace curry diff --git a/src/gamelib/world_moveable.cpp b/src/gamelib/world_moveable.cpp deleted file mode 100644 index 2e20957..0000000 --- a/src/gamelib/world_moveable.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright 2016-2018 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "world_moveable.hpp" -#include - -namespace curry { - WorldMoveable::WorldMoveable (const WorldSizeNotifiable::DeferredRegister& parDeferredRegister) : - WorldSizeNotifiable(parDeferredRegister), - m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f)), - m_world(parDeferredRegister.world()) - { - assert(m_world); - } - void WorldMoveable::world_size_changed (const vec2us&, const vec2i& parPixelSize) { - m_position.change_minmax(m_position.get_min(), vector_cast(parPixelSize)); - } - - void WorldMoveable::set_position (const vec2f& parPos) { - m_position = parPos; - } - - const vec2f& WorldMoveable::position() const { - return m_position.get(); - } - - void WorldMoveable::update_moveable_size (const vec2f& parOldSz, const vec2f& parNewSz) { - if (m_position.get_min() != m_position.get_max()) - m_position.change_minmax(m_position.get_min(), m_position.get_max() + parOldSz - parNewSz); - } - - WorldGrid& WorldMoveable::world() { - assert(m_world); - return *m_world; - } - - const WorldGrid& WorldMoveable::world() const { - assert(m_world); - return *m_world; - } -} //namespace curry diff --git a/src/gamelib/world_moveable.hpp b/src/gamelib/world_moveable.hpp deleted file mode 100644 index ec6492f..0000000 --- a/src/gamelib/world_moveable.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright 2016-2018 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#pragma once - -#include "moveable.hpp" -#include "worldsizenotifiable.hpp" -#include "constrained_position.hpp" - -namespace curry { - class WorldGrid; - - class WorldMoveable : public Moveable, public WorldSizeNotifiable { - public: - explicit WorldMoveable (const WorldSizeNotifiable::DeferredRegister& parDeferredRegister); - virtual ~WorldMoveable() = default; - - virtual void world_size_changed (const vec2us& parSize, const vec2i& parPixelSize) override; - const vec2f& position() const; - void set_position (const vec2f& parPos); - WorldGrid& world(); - const WorldGrid& world() const; - - protected: - void update_moveable_size (const vec2f& parOldSz, const vec2f& parNewSz); - - private: - ConstrainedPosition m_position; - WorldGrid* m_world; - }; -} //namespace curry diff --git a/src/gamelib/drawing_queue.cpp b/src/gamescenebase.cpp similarity index 55% rename from src/gamelib/drawing_queue.cpp rename to src/gamescenebase.cpp index 449c157..620f0f2 100644 --- a/src/gamelib/drawing_queue.cpp +++ b/src/gamescenebase.cpp @@ -17,25 +17,23 @@ along with MyCurry. If not, see . */ -#include "drawing_queue.hpp" +#include "gamescenebase.hpp" +#include "inputbag.hpp" #include "sdlmain.hpp" -#include "sizeratio.hpp" #include "rect_to_sdl.hpp" +#include "rect.hpp" #include "texture.hpp" -#include #include +#include +#include #include -#include -#include -#include -#include +#if !defined(NDEBUG) +# include "compatibility.h" +# include +#endif namespace curry { namespace { - typedef std::vector TextureList; - typedef std::vector LayerList; - typedef boost::container::flat_map LayerIdxMap; - #if !defined(NDEBUG) bool are_equal_rel (float parA, float parB, float parEpsilon) a_pure; @@ -45,6 +43,39 @@ namespace curry { } #endif + ///--------------------------------------------------------------------- + ///--------------------------------------------------------------------- + bool DoEvents (cloonel::InputBag& parInput, cloonel::SDLMain* parSdlMain) { + using cloonel::InputDevice_Keyboard; + + SDL_Event eve; + while (SDL_PollEvent(&eve)) { + switch (eve.type) { + case SDL_KEYDOWN: + //eve.key.keysym.sym + parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, true); + break; + + case SDL_KEYUP: + parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, false); + break; + + case SDL_QUIT: + return true; + + case SDL_WINDOWEVENT: + if (SDL_WINDOWEVENT_RESIZED == eve.window.event) { + parSdlMain->SetResolution(vec2us(static_cast(eve.window.data1), static_cast(eve.window.data2))); + } + else if (SDL_WINDOWEVENT_CLOSE == eve.window.event) { + return true; + } + break; + } + } + return false; + } + ///---------------------------------------------------------------------- ///Adjustes parSrc and parDest so that parDest will fit into parClip and ///parSrc to be the relevant part of the source texture to be drawn. @@ -94,85 +125,70 @@ namespace curry { } } //unnamed namespace - DrawingQueue::ItemInfo::ItemInfo() = default; - DrawingQueue::ItemInfo::ItemInfo (ItemInfo&&) = default; - DrawingQueue::ItemInfo::~ItemInfo() noexcept = default; - DrawingQueue::ItemInfo& DrawingQueue::ItemInfo::operator=(ItemInfo&&) = default; - - struct DrawingQueue::LocalData { - explicit LocalData (cloonel::SDLMain* parSDLMain) : - sdlmain(parSDLMain), - screen_res(0.0f), - def_layer_id(0) - { - } - - LayerList layers; - LayerIdxMap layer_idx_map; - cloonel::SDLMain* sdlmain; - vec2f screen_res; - std::size_t def_layer_id; - }; - - DrawingQueue::DrawingQueue (cloonel::SDLMain* parSDLMain, const cloonel::DeferredRegister& parDeferredRegister) : - SizeNotifiableBase(parSDLMain, parDeferredRegister), - m_local_data(new LocalData(parSDLMain)) + GameSceneBase::GameSceneBase (cloonel::SDLMain* parSdlMain) : + m_time0(std::chrono::steady_clock::now()), + m_input(std::make_unique()), + m_sdlmain(parSdlMain), + m_screen_width(static_cast(m_sdlmain->WidthHeight().x())), + m_screen_height(static_cast(m_sdlmain->WidthHeight().y())), + m_wants_to_quit(false) { - assert(parSDLMain); + assert(m_sdlmain); } - DrawingQueue::~DrawingQueue() noexcept = default; + GameSceneBase::~GameSceneBase() noexcept = default; - bool DrawingQueue::add_layer (uint16_t parName) { - auto& idx_map = m_local_data->layer_idx_map; - auto it_found = idx_map.lower_bound(parName); - if (it_found != idx_map.end() and it_found->first == parName) { - return false; - } - else { - m_local_data->layers.push_back(TextureList()); - const auto new_layer_index = m_local_data->layers.size() - 1; - idx_map.insert(it_found, std::make_pair(parName, new_layer_index)); - return true; - } + void GameSceneBase::prepare() { + m_wants_to_quit = false; + this->on_prepare(); + + m_time0 = std::chrono::steady_clock::now(); } - void DrawingQueue::flush_to_renderer() { - assert(not m_local_data->layers.empty()); - for (auto& layer : m_local_data->layers) { - for (auto& itm : layer) { - draw_clipped(*itm.texture, itm.source, itm.destination); - } - layer.clear(); - } + void GameSceneBase::destroy() noexcept { + set_wants_to_quit(); + this->on_destroy(); } - void DrawingQueue::add_for_rendering (uint16_t parName, ItemInfo&& parItem) { - const auto idx = m_local_data->layer_idx_map.at(parName); - auto& layers = m_local_data->layers; - assert(idx < layers.size()); - assert(parItem.source.is_valid()); - assert(parItem.destination.is_valid()); - assert(parItem.texture); - layers[idx].push_back(std::move(parItem)); - assert(not layers[idx].empty()); - assert(layers[idx].back().source.is_valid()); - assert(layers[idx].back().destination.is_valid()); + bool GameSceneBase::wants_to_quit() const { + return m_wants_to_quit; } - void DrawingQueue::draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest) { + void GameSceneBase::set_wants_to_quit() { + m_wants_to_quit = true; + } + + void GameSceneBase::exec() { + const auto time1 = std::chrono::steady_clock::now(); + + const bool quit = DoEvents(*m_input, m_sdlmain); + m_input->KeyStateUpdateFinished(); + if (quit) + set_wants_to_quit(); + + const float delta = std::chrono::duration(time1 - m_time0).count(); + m_time0 = time1; + this->on_update(delta); + SDL_RenderPresent(this->sdl_main()->GetRenderer()); + } + + cloonel::SDLMain* GameSceneBase::sdl_main() { + return m_sdlmain; + } + + cloonel::InputBag& GameSceneBase::input_bag() { + return *m_input; + } + + void GameSceneBase::draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest) { const vec2f lefttop(0.0f); - const vec2f& rightbottom = m_local_data->screen_res; + const vec2f rightbottom(m_screen_width, m_screen_height); clip_rect(parSrc, parDest, Rect(lefttop, rightbottom)); auto src = make_sdlrect(parSrc); auto dst = make_sdlrect(parDest); assert(src.w == dst.w); assert(src.h == dst.h); - SDL_RenderCopy(m_local_data->sdlmain->GetRenderer(), parTexture.texture(), &src, &dst); - } - - void DrawingQueue::OnResChanged (const cloonel::SizeRatio& parSizeRatio) { - m_local_data->screen_res = vec2f(cl_vec2us(parSizeRatio.Resolution())); + SDL_RenderCopy(m_sdlmain->GetRenderer(), parTexture.texture(), &src, &dst); } } //namespace curry diff --git a/src/gamelib/gamescenebase.hpp b/src/gamescenebase.hpp similarity index 91% rename from src/gamelib/gamescenebase.hpp rename to src/gamescenebase.hpp index d92599f..f5e072f 100644 --- a/src/gamelib/gamescenebase.hpp +++ b/src/gamescenebase.hpp @@ -28,8 +28,8 @@ namespace cloonel { } //namespace cloonel namespace curry { + class Texture; template class Rect; - class DrawingQueue; class GameSceneBase { public: @@ -50,13 +50,11 @@ namespace curry { virtual void on_update (float parDeltaT) = 0; cloonel::SDLMain* sdl_main(); cloonel::InputBag& input_bag(); - DrawingQueue& drawing_queue(); - const DrawingQueue& drawing_queue() const; + void draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest); private: std::chrono::time_point m_time0; std::unique_ptr m_input; - std::unique_ptr m_drawing_queue; cloonel::SDLMain* m_sdlmain; float m_screen_width; float m_screen_height; diff --git a/src/gamelib/ingamescene.cpp b/src/ingamescene.cpp similarity index 70% rename from src/gamelib/ingamescene.cpp rename to src/ingamescene.cpp index d7bfdfa..d2a15cd 100644 --- a/src/gamelib/ingamescene.cpp +++ b/src/ingamescene.cpp @@ -19,7 +19,7 @@ #include "ingamescene.hpp" #include "sdlmain.hpp" -#include "mycurry_toplevelConfig.h" +#include "mycurryConfig.h" #include "key.hpp" #include "inputbag.hpp" #include "movingobject.hpp" @@ -31,9 +31,6 @@ #include "csvloader.hpp" #include "worlditems.hpp" #include "gameactions.hpp" -#include "vector.hpp" -#include "drawing_queue.hpp" -#include "safe_stack_object.hpp" #include #include #include @@ -41,21 +38,15 @@ #include #include #include -#include namespace curry { namespace { - void add_layer_assert_done (DrawingQueue& parDQ, DrawaLayerNames parName) { - const bool layer_added = parDQ.add_layer(parName); - assert(layer_added); - static_cast(layer_added); - } } //unnamed namespace struct IngameScene::LocalData { LocalData (const vec2us& parTileSize, cloonel::SDLMain* parSDLMain, cloonel::InputBag* parInputBag) : world(parTileSize), - viewport(&world, vec2f(cl_vec2us(parSDLMain->WidthHeight())), WorldSizeNotifiable::DeferredRegister(&world, &viewport)), + viewport(&world, vec2f(parSDLMain->WidthHeight()), WorldSizeNotifiable::DeferredRegister(&world, &viewport)), player(parTileSize), character(parInputBag, WorldSizeNotifiable::DeferredRegister(&world, &character)) { @@ -63,7 +54,7 @@ namespace curry { WorldGrid world; WorldViewport viewport; - SafeStackObject worldtiles; + Texture worldtiles; MovingObject player; Character character; WorldItems moveable_items; @@ -81,18 +72,12 @@ namespace curry { inp.AddAction(ActionUp, Key(InputDevice_Keyboard, SDL_SCANCODE_UP), "Move up"); inp.AddAction(ActionRight, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right"); inp.AddAction(ActionDown, Key(InputDevice_Keyboard, SDL_SCANCODE_DOWN), "Move down"); - - add_layer_assert_done(drawing_queue(), DrawaLayerNames::Background); - add_layer_assert_done(drawing_queue(), DrawaLayerNames::Characters); -#if !defined(NDEBUG) - add_layer_assert_done(drawing_queue(), DrawaLayerNames::Debug); -#endif } IngameScene::~IngameScene() noexcept = default; void IngameScene::on_prepare() { - m_local_data->worldtiles->load(RESOURCES_PATH "nonfree_texture.png", *this->sdl_main(), RGBA{255, 255, 255, 0}); + m_local_data->worldtiles.load(RESOURCES_PATH "nonfree_texture.png", *this->sdl_main(), RGBA{255, 255, 255, 0}); CSVJointData tiles = load_csv({ RESOURCES_PATH "nonfree_map_ground.csv", RESOURCES_PATH "nonfree_map_transparent.csv" @@ -100,13 +85,12 @@ namespace curry { vec2us world_size(tiles.width, tiles.height); m_local_data->world.set_layers(world_size, tiles.tables); - m_local_data->world.set_tile_properties(tiles.tile_properties); #if !defined(NDEBUG) std::cout << "World size set to " << world_size << '\n'; #endif m_local_data->viewport.allow_overscan(false); - m_local_data->character.add_texture(RESOURCES_PATH "LPC_Sara_Preview.png", *this->sdl_main()); + m_local_data->character.load(RESOURCES_PATH "LPC_Sara_Preview.png", *this->sdl_main()); const float speed_per_sec = static_cast( std::max(m_local_data->world.tile_size().x(), m_local_data->world.tile_size().y()) @@ -124,9 +108,8 @@ namespace curry { m_local_data->moveable_items.move_items(parDeltaT); viewport.set_position(m_local_data->character.position() - (viewport.size() - m_local_data->character.width_height()) / 2.0f); - //TODO: move drawing code into the world map or something const auto tilesize(static_cast(world.tile_size())); - const auto tilecount(m_local_data->worldtiles->width_height() / world.tile_size()); + const auto tilecount(m_local_data->worldtiles.width_height() / world.tile_size()); for (auto tile : viewport) { for (uint16_t z = 0; z < m_local_data->world.layer_count(); ++z) { if (tile.index[z] < 0) @@ -137,24 +120,15 @@ namespace curry { Rect src_rect(src_rect_xy, src_rect_xy + tilesize); Rect dst_rect(pixel_pos, pixel_pos + tilesize); - this->draw(DrawaLayerNames::Background, m_local_data->worldtiles, src_rect, dst_rect); + this->draw_clipped(m_local_data->worldtiles, src_rect, dst_rect); } } - m_local_data->character.draw(drawing_queue(), viewport); + this->draw_clipped(m_local_data->character.texture(), m_local_data->character.source_rect(), m_local_data->character.destination_rect(viewport.position())); } void IngameScene::on_destroy() noexcept { m_local_data->moveable_items.unregister_all(); - m_local_data->worldtiles->unload(); - m_local_data->character.unload_textures(); - } - - void IngameScene::draw (DrawaLayerNames parLayer, Kakoune::SafePtr& parTexture, Rect parSrc, Rect parDest) { - DrawingQueue::ItemInfo item{}; - item.source = parSrc; - item.destination = parDest; - item.texture = parTexture; - drawing_queue().add_for_rendering(parLayer, std::move(item)); - assert(not item.texture); + m_local_data->worldtiles.unload(); + m_local_data->character.unload(); } } //namespace curry diff --git a/src/gamelib/ingamescene.hpp b/src/ingamescene.hpp similarity index 85% rename from src/gamelib/ingamescene.hpp rename to src/ingamescene.hpp index 7ff398c..55c8900 100644 --- a/src/gamelib/ingamescene.hpp +++ b/src/ingamescene.hpp @@ -20,18 +20,13 @@ #pragma once #include "gamescenebase.hpp" -#include "safe_ptr.hh" -#include "draw_layer_names.hpp" #include -#include namespace cloonel { class SDLMain; } //namespace cloonel namespace curry { - class Texture; - class IngameScene : public GameSceneBase { public: explicit IngameScene (cloonel::SDLMain* parSDLMain); @@ -41,7 +36,6 @@ namespace curry { virtual void on_prepare() override; virtual void on_destroy() noexcept override; virtual void on_update (float parDeltaT) override; - void draw (DrawaLayerNames parLayer, Kakoune::SafePtr& parTexture, Rect parSrc, Rect parDest); private: struct LocalData; diff --git a/src/inputbag.cpp b/src/inputbag.cpp new file mode 100644 index 0000000..e63b5b4 --- /dev/null +++ b/src/inputbag.cpp @@ -0,0 +1,150 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "inputbag.hpp" +#include "key.hpp" +#include +#include +#include +#include +#include + +namespace cloonel { + struct Action { + Key key; + const std::string name; + InputBag::ActionStateType state; + bool newStatePressed; + + bool operator== ( const Key& parKey ) const { return key == parKey; } + }; + + struct InputBag::LocalData { + std::vector actions; + std::map mappings; + }; + + namespace { + // | rl | pr + // ----------------- + // rel | rel | jpr + // prs | jrl | prs + // jrl | rel | jpr + // jpr | jrl | prs + const InputBag::ActionStateType g_stateTruthTable[] = { + InputBag::ActionState_Released, + InputBag::ActionState_JustReleased, + InputBag::ActionState_Released, + InputBag::ActionState_JustReleased, + InputBag::ActionState_JustPressed, + InputBag::ActionState_Pressed, + InputBag::ActionState_JustPressed, + InputBag::ActionState_Pressed + }; + + ///---------------------------------------------------------------------- + ///When actions vector is reallocated, update pointers in mappings. + ///---------------------------------------------------------------------- + void UpdatePointers (Action* parOldAddrStart, Action* parNewAddress, std::map& parUpdate, int parOffset) { + for (auto& itMap : parUpdate) { + if (itMap.second >= parOldAddrStart) { + itMap.second = parNewAddress + (itMap.second - parOldAddrStart) + parOffset; + } + } + } + } //unnamed namespace + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + InputBag::InputBag() : + m_localdata(new LocalData) + { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + InputBag::~InputBag() noexcept { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::AddAction (int parAction, const Key& parKey, std::string&& parName) { + Action* const oldBuff = m_localdata->actions.data(); + m_localdata->actions.push_back(Action({parKey, parName, ActionState_Released, false})); + Action* const newBuff = m_localdata->actions.data(); + if (oldBuff != newBuff) { + UpdatePointers(oldBuff, newBuff, m_localdata->mappings, 0); + } + m_localdata->mappings[parAction] = &m_localdata->actions.back(); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + InputBag::ActionStateType InputBag::ActionState (int parAction) const { + assert(m_localdata->mappings.find(parAction) != m_localdata->mappings.end()); + return m_localdata->mappings[parAction]->state; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::Clear() { + m_localdata->actions.clear(); + m_localdata->mappings.clear(); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::NotifyKeyAction (InputDeviceType parDev, int parScancode, bool parPressed) { + const Key searchKey(parDev, parScancode); + auto itFound = std::find(m_localdata->actions.begin(), m_localdata->actions.end(), searchKey); + //This method gets called every time a keypress or keyrelease is + //produced, but if the key is of any use is decided here. So it possible + //that a keystroke is not bound to any action and therefore no + //corresponding element is present in the actions list. + if (m_localdata->actions.end() != itFound) + itFound->newStatePressed = parPressed; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::KeyStateUpdateFinished() noexcept { + for (auto& currAction : m_localdata->actions) { + const int numericState = static_cast(currAction.state); + assert(numericState < 4); + const int index = (currAction.newStatePressed ? 4 : 0) + numericState; + currAction.state = g_stateTruthTable[index]; + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::ClearState() { + for (auto& currAction : m_localdata->actions) { + currAction.newStatePressed = false; + currAction.state = ActionState_Released; + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + bool IsPressed (const InputBag& parInput, int parAction) { + const InputBag::ActionStateType state = parInput.ActionState(parAction); + return InputBag::ActionState_Pressed == state or InputBag::ActionState_JustPressed == state; + } +} //namespace cloonel diff --git a/src/inputbag.hpp b/src/inputbag.hpp new file mode 100644 index 0000000..3b96040 --- /dev/null +++ b/src/inputbag.hpp @@ -0,0 +1,59 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef idF4E67FC292A5480DA4305B806170F520 +#define idF4E67FC292A5480DA4305B806170F520 + +#include "inputdevicetype.hpp" +#include +#include + +namespace cloonel { + struct Key; + + class InputBag { + public: + enum ActionStateType { + ActionState_Released, + ActionState_Pressed, + ActionState_JustReleased, + ActionState_JustPressed + }; + + InputBag ( void ); + ~InputBag ( void ) noexcept; + + void AddAction ( int parAction, const Key& parKey, std::string&& parName ); + ActionStateType ActionState ( int parAction ) const; + void Clear ( void ); + void NotifyKeyAction ( InputDeviceType parDev, int parScancode, bool parPressed ); + void KeyStateUpdateFinished ( void ) noexcept; + void ClearState ( void ); + + private: + struct LocalData; + + const std::unique_ptr m_localdata; + }; + + bool IsPressed ( const InputBag& parInput, int parAction ); + inline bool IsReleased ( const InputBag& parInput, int parAction ) { return not IsPressed(parInput, parAction); } +} //namespace cloonel + +#endif diff --git a/src/inputdevicetype.hpp b/src/inputdevicetype.hpp new file mode 100644 index 0000000..3058e38 --- /dev/null +++ b/src/inputdevicetype.hpp @@ -0,0 +1,29 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef idED0C5C9767B64910A2998ACDAE14A509 +#define idED0C5C9767B64910A2998ACDAE14A509 + +namespace cloonel { + enum InputDeviceType { + InputDevice_Keyboard + }; +} //namespace cloonel + +#endif diff --git a/src/key.hpp b/src/key.hpp new file mode 100644 index 0000000..bd25baf --- /dev/null +++ b/src/key.hpp @@ -0,0 +1,62 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef id8F6145D6CFBA40338C5804DEC032CE16 +#define id8F6145D6CFBA40338C5804DEC032CE16 + +#include "inputdevicetype.hpp" +#include + +namespace cloonel { + struct Key { + Key ( void ) = default; + Key ( InputDeviceType parDev, int parScancode, const char parLabel[4] ) : + srcdevice(parDev), + scancode(parScancode) + { + label[0] = parLabel[0]; + label[1] = parLabel[1]; + label[2] = parLabel[2]; + label[3] = parLabel[3]; + } + Key ( InputDeviceType parDev, int parScancode ) : + srcdevice(parDev), + scancode(parScancode), + label {0, 0, 0, 0} + { + } + ~Key ( void ) noexcept = default; + + bool operator== ( const Key& parOther ) const { + return srcdevice == parOther.srcdevice and scancode == parOther.scancode; + } + bool operator!= ( const Key& parOther ) const { + return not this->operator==(parOther); + } + bool operator< ( const Key& parOther ) const { + return (srcdevice == parOther.srcdevice and scancode < parOther.scancode) or (srcdevice < parOther.srcdevice); + } + + InputDeviceType srcdevice; + int scancode; + char label[4]; + }; +} //namespace cloonel + +#endif diff --git a/src/standalone/main.cpp b/src/main.cpp similarity index 96% rename from src/standalone/main.cpp rename to src/main.cpp index 8c27a81..88c42a6 100644 --- a/src/standalone/main.cpp +++ b/src/main.cpp @@ -48,10 +48,6 @@ int main() { cloonel::ushort2(REFERENCE_WIDTH, REFERENCE_HEIGHT) ); -#if !defined(NDEBUG) - std::cout << "Debug build\n"; -#endif - int ret_val = 0; try { sdl_main.Init(); diff --git a/src/gamelib/moveable.cpp b/src/moveable.cpp similarity index 100% rename from src/gamelib/moveable.cpp rename to src/moveable.cpp diff --git a/src/gamelib/moveable.hpp b/src/moveable.hpp similarity index 100% rename from src/gamelib/moveable.hpp rename to src/moveable.hpp diff --git a/src/gamelib/movingobject.cpp b/src/movingobject.cpp similarity index 100% rename from src/gamelib/movingobject.cpp rename to src/movingobject.cpp diff --git a/src/gamelib/movingobject.hpp b/src/movingobject.hpp similarity index 100% rename from src/gamelib/movingobject.hpp rename to src/movingobject.hpp diff --git a/src/mycurry_toplevelConfig.h.in b/src/mycurryConfig.h.in similarity index 96% rename from src/mycurry_toplevelConfig.h.in rename to src/mycurryConfig.h.in index ac6f3c4..165dab5 100644 --- a/src/mycurry_toplevelConfig.h.in +++ b/src/mycurryConfig.h.in @@ -20,4 +20,3 @@ #pragma once #define RESOURCES_PATH "@MYCURRY_RESOURCES_PATH@/" -#cmakedefine BUILD_TESTING diff --git a/src/observersmanager.hpp b/src/observersmanager.hpp new file mode 100644 index 0000000..926c532 --- /dev/null +++ b/src/observersmanager.hpp @@ -0,0 +1,180 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef idF5E41734950640CDA3C949E0D3A9A30D +#define idF5E41734950640CDA3C949E0D3A9A30D + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (WITH_VERBOSE_OBS_MANAGER) && defined(__GNUC__) && __GNUC__ >= 2 && !defined(NDEBUG) +# define OBS_MANAGER_LOG +#endif + +#if defined(OBS_MANAGER_LOG) +# include +#endif + +namespace cloonel { + template + class ObserversManager { + public: + typedef size_t TicketType; + + private: + struct TicketedWrapper { + TicketedWrapper ( void ) = default; + TicketedWrapper ( T parItem, TicketType parTicket ) : + itm(parItem), + ticket(parTicket) + { + } + + T itm; + TicketType ticket; + + bool operator== ( const TicketedWrapper& parOther ) const { return parOther.ticket == ticket; } + bool operator== ( TicketType parOther ) const { return parOther == ticket; } + }; + static T& TicketedWrapperToItm ( TicketedWrapper& parWrapper ) { return parWrapper.itm; } + + typedef tree TreeType; + typedef typename tree::iterator TreeIteratorType; + + public: + enum { + Ticket_Null = 0 + }; + typedef boost::transform_iterator, TreeIteratorType> iterator; + + ObserversManager ( void ); + ~ObserversManager ( void ) noexcept; + + TicketType Add ( T parObserver, TicketType parParent=Ticket_Null ); + void Remove ( TicketType parTicket ) noexcept; + void RemoveAll ( void ) noexcept; + void Update ( TicketType parTicket, T parObserver ); + std::size_t size ( void ) const { return m_tree.size(); } + iterator begin ( void ) { return iterator(m_tree.begin(), &TicketedWrapperToItm); } + iterator end ( void ) { return iterator(m_tree.end(), &TicketedWrapperToItm); } + void CopyObservers ( std::unordered_set& parOut ); + + private: + TreeIteratorType GetByTicket_AssertPresent ( TicketType parTicket ); + + TreeType m_tree; + TicketType m_nextTicket; + }; + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + ObserversManager::ObserversManager() : + m_nextTicket(1) + { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + ObserversManager::~ObserversManager() noexcept { + assert(m_tree.empty()); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + typename ObserversManager::TicketType ObserversManager::Add (T parObserver, TicketType parParent) { + const auto currTicket = m_nextTicket; + if (Ticket_Null == parParent) + m_tree.insert(m_tree.begin(), TicketedWrapper(parObserver, currTicket)); + else + m_tree.append_child(GetByTicket_AssertPresent(parParent), TicketedWrapper(parObserver, currTicket)); + +#if defined(OBS_MANAGER_LOG) + std::cout << __PRETTY_FUNCTION__ << " registering " << currTicket << " as a child of " << parParent << "\n"; +#endif + ++m_nextTicket; + return currTicket; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + void ObserversManager::Remove (TicketType parTicket) noexcept { + auto deleme = GetByTicket_AssertPresent(parTicket); +#if defined(OBS_MANAGER_LOG) + for (auto it(deleme); it != m_tree.end(); ++it) { + std::cout << __PRETTY_FUNCTION__ << " unregistering " << it->ticket << "\n"; + } +#endif + m_tree.erase(deleme); + if (parTicket == m_nextTicket - 1) + --m_nextTicket; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + void ObserversManager::RemoveAll() noexcept { + if (not m_tree.empty()) { + for (typename TreeType::sibling_iterator it(m_tree.begin()), itEND(m_tree.end()); it != itEND; ++it) { + const TicketType ticket = it->ticket; + this->Remove(ticket); + } + assert(m_tree.empty()); + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + void ObserversManager::Update (TicketType parTicket, T parObserver) { + std::swap(GetByTicket_AssertPresent(parTicket)->itm, parObserver); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + typename ObserversManager::TreeIteratorType ObserversManager::GetByTicket_AssertPresent (TicketType parTicket) { + auto ret = std::find(m_tree.begin(), m_tree.end(), parTicket); + assert(m_tree.end() != ret); + return ret; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + void ObserversManager::CopyObservers (std::unordered_set& parOut) { + for (const auto& itm : m_tree) { + parOut.insert(itm.itm); + } + } +} //namespace cloonel + +#if defined(OBS_MANAGER_LOG) +# undef OBS_MANAGER_LOG +#endif +#endif diff --git a/src/gamelib/rect.hpp b/src/rect.hpp similarity index 100% rename from src/gamelib/rect.hpp rename to src/rect.hpp diff --git a/src/gamelib/rect_to_sdl.cpp b/src/rect_to_sdl.cpp similarity index 100% rename from src/gamelib/rect_to_sdl.cpp rename to src/rect_to_sdl.cpp diff --git a/src/gamelib/rect_to_sdl.hpp b/src/rect_to_sdl.hpp similarity index 100% rename from src/gamelib/rect_to_sdl.hpp rename to src/rect_to_sdl.hpp diff --git a/src/sdlmain.cpp b/src/sdlmain.cpp new file mode 100644 index 0000000..2d0d9df --- /dev/null +++ b/src/sdlmain.cpp @@ -0,0 +1,236 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "sdlmain.hpp" +#include "observersmanager.hpp" +#include "sizenotifiable.hpp" +#include "sizeratio.hpp" +#include +#include +#include +#include +#include +#include + +#if defined(RASPBERRY_PI) +#include +#endif + +namespace cloonel { + namespace { + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + std::pair GetRenderingDriver() { + typedef std::pair RetPairType; + + const int count = SDL_GetNumRenderDrivers(); + int opengles = -1; + int opengles2 = -1; + int opengl = -1; + SDL_RendererInfo info; + for (int z = 0; z < count; ++z) { + const int ret = SDL_GetRenderDriverInfo(z, &info); + if (0 == ret) { + if (std::strcmp("opengles", info.name) == 0) + opengles = z; + else if (std::strcmp("opengles2", info.name) == 0) + opengles2 = z; + else if (std::strcmp("opengl", info.name) == 0) + opengl = z; + } + } +#if !defined(FORCE_OPENGLES) + if (opengl > -1) + return RetPairType(opengl, "opengl"); +#endif + if (opengles2 > -1) + return RetPairType(opengles2, "opengles2"); + if (opengles > -1) + return RetPairType(opengles, "opengles"); +#if defined(FORCE_OPENGLES) + if (opengl > -1) + return RetPairType(opengl, "opengl"); +#endif + + return RetPairType(-1, "default"); + } + } //unnamed namespace + + struct SDLMain::LocalData { + SDL_Window* window; + SDL_Renderer* renderer; + SizeRatio sizeratio; + ObserversManager resChangeNotifList; + bool initialized; +#if defined(RASPBERRY_PI) + bool bcmInitialized; +#endif + }; + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + SDLMain::SDLMain (const char* parGameName, ushort2 parRes, ushort2 parReferenceRes) : + m_gameName(parGameName), + m_localData(new LocalData) + { + m_localData->sizeratio.SetOriginal(static_cast(parReferenceRes), static_cast(parRes)); + m_localData->initialized = false; +#if defined(RASPBERRY_PI) + m_localData->bcmInitialized = false; +#endif + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + SDLMain::~SDLMain() noexcept { + ClearIFN(*m_localData); +#if defined(RASPBERRY_PI) + assert(not m_localData->bcmInitialized); +#endif + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + void SDLMain::Init() { + if (not m_localData->initialized) + InitSDL(*m_localData); + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + void SDLMain::InitSDL (LocalData& parInitSDL) { +#if defined(RASPBERRY_PI) + assert(not parInitSDL.bcmInitialized); + bcm_host_init(); + parInitSDL.bcmInitialized = true; +#endif + + parInitSDL.window = nullptr; + parInitSDL.renderer = nullptr; + parInitSDL.initialized = false; + + if (SDL_Init(SDL_INIT_EVERYTHING) == -1) + throw std::runtime_error(SDL_GetError()); + parInitSDL.initialized = true; + +#if defined(FORCE_OPENGLES) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); +#endif + + const float2 wh(m_localData->sizeratio.Resolution()); + SDL_Window* const win = SDL_CreateWindow(m_gameName.c_str(), 100, 100, static_cast(wh.x()), static_cast(wh.y()), SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + if (!win) + throw std::runtime_error(SDL_GetError()); + parInitSDL.window = win; + + const auto rendererDriver = GetRenderingDriver(); + m_rendererName = rendererDriver.second; + SDL_Renderer* const renderer = SDL_CreateRenderer(win, rendererDriver.first, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!renderer) + throw std::runtime_error(SDL_GetError()); + parInitSDL.renderer = renderer; + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + void SDLMain::ClearIFN (LocalData& parInitSDL) noexcept { + if (parInitSDL.renderer) + SDL_DestroyRenderer(parInitSDL.renderer); + if (parInitSDL.window) + SDL_DestroyWindow(parInitSDL.window); + if (parInitSDL.initialized) { + parInitSDL.initialized = false; + SDL_Quit(); + } +#if defined(RASPBERRY_PI) + if (parInitSDL.bcmInitialized) { + parInitSDL.bcmInitialized = false; + bcm_host_deinit(); + } +#endif + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + SDL_Renderer* SDLMain::GetRenderer() { + if (m_localData->initialized) + return m_localData->renderer; + else + return nullptr; + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + void SDLMain::SetResolution (ushort2 parRes) { + m_localData->sizeratio.UpdateResolution(static_cast(parRes)); + { + SDL_Renderer* const renderer = GetRenderer(); + assert(renderer); + const int retVal = SDL_RenderSetLogicalSize(renderer, parRes.x(), parRes.y()); + if (retVal) { + std::ostringstream oss; + oss << "Error setting logical size to renderer to " << parRes.x() << "x" << parRes.y() << ": " << SDL_GetError(); + throw std::runtime_error(oss.str()); + } + + const SDL_Rect area = { 0, 0, parRes.x(), parRes.y() }; + const int retValViewport = SDL_RenderSetViewport(renderer, &area); + if (retValViewport) { + std::ostringstream oss; + oss << "Error setting viewport to renderer to " << parRes.x() << "x" << parRes.y() << ": " << SDL_GetError(); + throw std::runtime_error(oss.str()); + } + } + + for (auto currNotifiable : m_localData->resChangeNotifList) { + currNotifiable->NotifyResChanged(m_localData->sizeratio); + } + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + size_t SDLMain::RegisterForResChange (SizeNotifiableBase* parNotif) { + parNotif->NotifyResChanged(m_localData->sizeratio); + return m_localData->resChangeNotifList.Add(parNotif); + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + void SDLMain::UnregisterForResChange (size_t parID) noexcept { + m_localData->resChangeNotifList.Remove(parID); + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + void SDLMain::SwapRegisteredForResChange (size_t parID, SizeNotifiableBase* parNotif) { + m_localData->resChangeNotifList.Update(parID, parNotif); + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + ushort2 SDLMain::WidthHeight() const noexcept { + return static_cast(m_localData->sizeratio.Resolution()); + } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + std::string SDLMain::GetVideoDriverName() const { + return std::string(SDL_GetCurrentVideoDriver()); + } +} //namespace cloonel diff --git a/src/sdlmain.hpp b/src/sdlmain.hpp new file mode 100644 index 0000000..dc05b8c --- /dev/null +++ b/src/sdlmain.hpp @@ -0,0 +1,60 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef id8E7A054DAC9040B887F2620EFD229EE8 +#define id8E7A054DAC9040B887F2620EFD229EE8 + +#include "vector.hpp" +#include +#include + +struct SDL_Renderer; + +namespace cloonel { + class SizeNotifiableBase; + + class SDLMain { + public: + SDLMain ( const char* parGameName, ushort2 parRes, ushort2 parReferenceRes ); + ~SDLMain ( void ) noexcept; + + void Init ( void ); + SDL_Renderer* GetRenderer ( void ); + ushort2 WidthHeight ( void ) const noexcept; + + void SetResolution ( ushort2 parRes ); + size_t RegisterForResChange ( SizeNotifiableBase* parNotif ); + void UnregisterForResChange ( size_t parID ) noexcept; + void SwapRegisteredForResChange ( size_t parID, SizeNotifiableBase* parNotif ); + const std::string& GetRendererName ( void ) const { return m_rendererName; } + std::string GetVideoDriverName ( void ) const; + + private: + struct LocalData; + + void InitSDL ( LocalData& parData ); + void ClearIFN ( LocalData& parData ) noexcept; + + const std::string m_gameName; + std::string m_rendererName; + std::unique_ptr m_localData; + }; +} //namespace cloonel + +#endif diff --git a/src/gamelib/tileproperty.hpp b/src/singlecoordinate.cpp similarity index 78% rename from src/gamelib/tileproperty.hpp rename to src/singlecoordinate.cpp index 35717fa..781d3dc 100644 --- a/src/gamelib/tileproperty.hpp +++ b/src/singlecoordinate.cpp @@ -17,15 +17,10 @@ along with MyCurry. If not, see . */ -#pragma once +#include "singlecoordinate.hpp" +#include "coordinates.hpp" namespace curry { - struct TileProperty { - TileProperty() : - walkable(true) - { - } - - bool walkable; - }; + static_assert(implem::Log2<256>::result == 8, "Wrong logarithm result"); + static_assert(implem::Log2<255>::result == 7, "Wrong logarithm result"); } //namespace curry diff --git a/src/singlecoordinate.hpp b/src/singlecoordinate.hpp new file mode 100644 index 0000000..2ca9460 --- /dev/null +++ b/src/singlecoordinate.hpp @@ -0,0 +1,110 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#pragma once + +#include "vector.hpp" +#include +#include +#include + +namespace curry { + namespace implem { + template 0)> + struct Log2; + + template + struct Log2 { + static constexpr const uint32_t b[5] = {0x2, 0xc, 0xf0, 0xff00, 0xffff0000}; + static constexpr const uint32_t S[5] = {1, 2, 4, 8, 16}; + enum { + result = Log2<(V & b[I - 1] ? V >> S[I - 1] : V), (V & b[I - 1] ? R | S[I - 1] : R), I - 1>::result + }; + }; + template + struct Log2 { + enum { + result = R + }; + }; + + template + struct NextPow2 { + static_assert(V > 0, "V must be greater than zero"); + enum { + result = (1U << Log2::result) + 1 + }; + }; + } //namespace implem + + class SingleCoordinate { + public: + SingleCoordinate() = default; + SingleCoordinate (const SingleCoordinate&) = default; + explicit SingleCoordinate (uint32_t parTile); + SingleCoordinate (uint32_t parTile, uint32_t parOffset); + ~SingleCoordinate() noexcept = default; + + int32_t screen_coordinate (int32_t parWorldOffset, uint32_t parTileSize) const; + uint32_t tile() const; + + private: + static constexpr const auto MaxTileSize = 128U; + static constexpr const auto OffsetBits = implem::Log2::result; + static constexpr const auto OffsetMask = implem::NextPow2::result - 1; + + uint32_t m_data; + }; + + inline int32_t SingleCoordinate::screen_coordinate (int32_t parWorldOffset, uint32_t parTileSize) const { + assert(parTileSize <= MaxTileSize); + return ((m_data - parWorldOffset) & OffsetMask) + + (static_cast(m_data - parWorldOffset) >> OffsetBits) * parTileSize; + } + + inline uint32_t SingleCoordinate::tile() const { + int beyond_tile; + const int offset = m_data & OffsetMask; + asm( + "xorl %%eax,%%eax\n\t" + "subl %1,%%eax\n\t" + "xorl %%eax,%%eax\n\t" + "adcl %%eax,0\n\t" + "movl %%eax,%0" + :"=r"(beyond_tile) + :"r"(offset) + :"%eax" + ); + assert(0 == beyond_tile or 1 == beyond_tile); + return (m_data >> OffsetBits) + beyond_tile; + } + + SingleCoordinate::SingleCoordinate (uint32_t parTile) : + m_data(parTile << OffsetBits) + { + assert(this->tile() == parTile); + } + + SingleCoordinate::SingleCoordinate (uint32_t parTile, uint32_t parOffset) : + m_data((parTile << OffsetBits) + (parOffset & OffsetMask)) + { + assert((not parOffset and this->tile() == parTile) or (this->tile() == parTile + 1)); + assert((m_data bitand OffsetMask) == parOffset); + } +} //namespace curry diff --git a/src/sizenotifiable.cpp b/src/sizenotifiable.cpp new file mode 100644 index 0000000..7d6750d --- /dev/null +++ b/src/sizenotifiable.cpp @@ -0,0 +1,78 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#include "sizenotifiable.hpp" +#include "sizeratio.hpp" +#include "sdlmain.hpp" +#include +#include + +namespace cloonel { + namespace implem { + } //namespace implem + + namespace regbehaviours { + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + void AutoRegister::Register (SizeNotifiableBase* parNotifiable) { + assert(m_sdlmain); +#if !defined(NDEBUG) + assert(not m_registered); + m_registered = true; +#endif + m_id = m_sdlmain->RegisterForResChange(parNotifiable); + } + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + void AutoRegister::Unregister() noexcept { +#if !defined(NDEBUG) + assert(m_registered or not m_sdlmain); + m_registered = false; +#endif + if (m_sdlmain) { + m_sdlmain->UnregisterForResChange(m_id); + } + } + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + AutoRegister::AutoRegister (AutoRegister&& parOther, SizeNotifiableBase* parSwapTo) : + m_sdlmain(nullptr), + m_id(0) +#if !defined(NDEBUG) + , m_registered(false) +#endif + { + std::swap(m_sdlmain, parOther.m_sdlmain); + std::swap(m_id, parOther.m_id); +#if !defined(NDEBUG) + std::swap(m_registered, parOther.m_registered); +#endif + assert(m_sdlmain); + m_sdlmain->SwapRegisteredForResChange(m_id, parSwapTo); + } + } //namespace regbehaviours + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void SizeNotifiableBase::NotifyResChanged (const SizeRatio& parSize) { + m_scaleRatio = parSize.Ratio(); + } +} //namespace cloonel diff --git a/src/sizenotifiable.hpp b/src/sizenotifiable.hpp new file mode 100644 index 0000000..132cf34 --- /dev/null +++ b/src/sizenotifiable.hpp @@ -0,0 +1,128 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef id78906DE4FB0D43219CD3F0D9C620FC06 +#define id78906DE4FB0D43219CD3F0D9C620FC06 + +#include "vector.hpp" +#include +#include + +namespace cloonel { + class SizeRatio; + class SDLMain; + class SizeNotifiableBase; + + namespace regbehaviours { + class DontRegister { + public: + enum { SDLMAIN_NEEDED = false }; + + DontRegister ( void ) = default; + DontRegister ( DontRegister&&, SizeNotifiableBase* ) { } + ~DontRegister ( void ) noexcept = default; + + void Register ( SizeNotifiableBase* ) const noexcept { return; } + void Unregister ( void ) const noexcept { return; } + }; + + class AutoRegister { + public: + enum { SDLMAIN_NEEDED = true }; + + AutoRegister ( AutoRegister&& parOther, SizeNotifiableBase* parSwapTo ); + explicit AutoRegister ( SDLMain* parMain ) : + m_sdlmain(parMain) +#if !defined(NDEBUG) + , m_registered(false) +#endif + { + } + ~AutoRegister ( void ) noexcept = default; + + void Register ( SizeNotifiableBase* parNotifiable ); + void Unregister ( void ) noexcept; + + private: + SDLMain* m_sdlmain; + size_t m_id; +#if !defined(NDEBUG) + bool m_registered; +#endif + }; + } //namespace regbehaviours + + class SizeNotifiableBase { + protected: + SizeNotifiableBase ( void ) = default; + SizeNotifiableBase ( const SizeNotifiableBase& ) = default; + virtual ~SizeNotifiableBase ( void ) noexcept = default; + SizeNotifiableBase& operator= ( const SizeNotifiableBase& ) = delete; + + public: + virtual void NotifyResChanged ( const SizeRatio& parSize ); + const float2& Ratio ( void ) const noexcept { return m_scaleRatio; } + + private: + float2 m_scaleRatio; + }; + + template + class SizeNotifiable; + + template + class SizeNotifiable : private RegisterBehaviour, public SizeNotifiableBase { + static_assert(RegisterBehaviour::SDLMAIN_NEEDED == false, "SdlMainNeeded mismatches expected value"); + public: + SizeNotifiable ( const SizeNotifiable& ) = delete; + SizeNotifiable ( SizeNotifiable&& parOther ) : + RegisterBehaviour(std::move(parOther), this), + SizeNotifiableBase(parOther) + { + } + SizeNotifiable ( void ) { + this->Register(this); + } + virtual ~SizeNotifiable ( void ) noexcept { + this->Unregister(); + } + }; + + template + class SizeNotifiable : private RegisterBehaviour, public SizeNotifiableBase { + static_assert(RegisterBehaviour::SDLMAIN_NEEDED == true, "SdlMainNeeded mismatches expected value"); + public: + SizeNotifiable ( const SizeNotifiable& ) = delete; + SizeNotifiable ( SizeNotifiable&& parOther ) : + RegisterBehaviour(std::move(parOther), this), + SizeNotifiableBase(parOther) + { + } + explicit SizeNotifiable ( SDLMain* parSdlMain ) : + RegisterBehaviour(parSdlMain) + { + this->Register(this); + } + virtual ~SizeNotifiable ( void ) noexcept { + this->Unregister(); + } + }; +} //namespace cloonel + +#endif diff --git a/src/sizeratio.cpp b/src/sizeratio.cpp new file mode 100644 index 0000000..53a7af7 --- /dev/null +++ b/src/sizeratio.cpp @@ -0,0 +1,66 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#include "sizeratio.hpp" +#include "compatibility.h" + +namespace cloonel { + namespace { + float2 CalculateRatio ( float2 parOriginal, float2 parResolution ) a_pure; + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + float2 CalculateRatio (float2 parOriginal, float2 parResolution) { + return parResolution / parOriginal; + } + } //unnamed namespace + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + SizeRatio::SizeRatio (const float2& parOriginal) : + m_original(parOriginal), + m_size(parOriginal), + m_ratio(1.0f) + { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + SizeRatio::SizeRatio (const float2& parOriginal, const float2& parSize) : + m_original(parOriginal), + m_size(parSize), + m_ratio(CalculateRatio(parOriginal, parSize)) + { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void SizeRatio::SetOriginal (const float2& parOriginal, const float2& parRes) { + m_original = parOriginal; + m_size = parRes; + m_ratio = CalculateRatio(parOriginal, parRes); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void SizeRatio::UpdateResolution (const float2& parNewRes) { + m_size = parNewRes; + m_ratio = CalculateRatio(m_original, parNewRes); + } +} //namespace cloonel diff --git a/src/sizeratio.hpp b/src/sizeratio.hpp new file mode 100644 index 0000000..6e0cc4f --- /dev/null +++ b/src/sizeratio.hpp @@ -0,0 +1,45 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef id3098F08C14B84E3C8CE169CBA05C9C86 +#define id3098F08C14B84E3C8CE169CBA05C9C86 + +#include "vector.hpp" + +namespace cloonel { + class SizeRatio { + public: + SizeRatio ( void ) = default; + explicit SizeRatio ( const float2& parOriginal ); + SizeRatio ( const float2& parOriginal, const float2& parSize ); + ~SizeRatio ( void ) noexcept = default; + + const float2& Ratio ( void ) const noexcept { return m_ratio; } + const float2& Resolution ( void ) const noexcept { return m_size; } + void SetOriginal ( const float2& parOriginal, const float2& parRes ); + void UpdateResolution ( const float2& parNewRes ); + + private: + float2 m_original; + float2 m_size; + float2 m_ratio; + }; +} //namespace cloonel + +#endif diff --git a/src/standalone/CMakeLists.txt b/src/standalone/CMakeLists.txt deleted file mode 100644 index a44913f..0000000 --- a/src/standalone/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -project(mycurry CXX) - -add_executable(${PROJECT_NAME} - main.cpp -) -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14) -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) - -target_include_directories(${PROJECT_NAME} - PRIVATE "${CMAKE_SOURCE_DIR}/src/gamelib" - PRIVATE ${CMAKE_BINARY_DIR} - PRIVATE ${CMAKE_SOURCE_DIR}/lib/DeathHandler -) - -target_link_libraries(${PROJECT_NAME} - PRIVATE mycurry_gamelib -) diff --git a/src/gamelib/texture.cpp b/src/texture.cpp similarity index 86% rename from src/gamelib/texture.cpp rename to src/texture.cpp index 8e164b4..2eba3ea 100644 --- a/src/gamelib/texture.cpp +++ b/src/texture.cpp @@ -73,20 +73,6 @@ namespace curry { m_texture = load_texture(parPath, parSDLMain, true, parColorKey); } - void Texture::load_empty (cloonel::SDLMain& parSDLMain, const vec2us& parSize) { - assert(parSize > static_cast(0)); - m_texture = SDLTextureAuto( - SDL_CreateTexture( - parSDLMain.GetRenderer(), - SDL_PIXELFORMAT_RGBA8888, - SDL_TEXTUREACCESS_TARGET, - static_cast(parSize.x()), - static_cast(parSize.y()) - ), - &SDL_DestroyTexture - ); - } - void Texture::unload() noexcept { m_texture.reset(nullptr); } diff --git a/src/gamelib/texture.hpp b/src/texture.hpp similarity index 86% rename from src/gamelib/texture.hpp rename to src/texture.hpp index 12ab27c..f6a2003 100644 --- a/src/gamelib/texture.hpp +++ b/src/texture.hpp @@ -20,7 +20,6 @@ #pragma once #include "vector.hpp" -#include "safe_ptr.hh" #include #include @@ -38,17 +37,14 @@ namespace curry { uint8_t a; }; - class Texture : public Kakoune::SafeCountable { + class Texture { public: Texture(); Texture (const char* parPath, cloonel::SDLMain& parSDLMain); - Texture (Texture&&) = default; - Texture (const Texture&) = delete; ~Texture() noexcept; void load (const char* parPath, cloonel::SDLMain& parSDLMain); void load (const char* parPath, cloonel::SDLMain& parSDLMain, RGBA parColorKey); - void load_empty (cloonel::SDLMain& parSDLMain, const vec2us& parSize); void unload() noexcept; SDL_Texture* texture(); const SDL_Texture* texture() const; diff --git a/src/gamelib/tileindextype.hpp b/src/tileindextype.hpp similarity index 100% rename from src/gamelib/tileindextype.hpp rename to src/tileindextype.hpp diff --git a/src/gamelib/tileiterator.cpp b/src/tileiterator.cpp similarity index 100% rename from src/gamelib/tileiterator.cpp rename to src/tileiterator.cpp diff --git a/src/gamelib/tileiterator.hpp b/src/tileiterator.hpp similarity index 100% rename from src/gamelib/tileiterator.hpp rename to src/tileiterator.hpp diff --git a/src/gamelib/vector.hpp b/src/vector.hpp similarity index 77% rename from src/gamelib/vector.hpp rename to src/vector.hpp index 34c2221..2546b94 100644 --- a/src/gamelib/vector.hpp +++ b/src/vector.hpp @@ -20,7 +20,6 @@ #pragma once #include "vectorwrapper/vectorwrapper.hpp" -#include "vectypes.hpp" #include #include #if !defined(NDEBUG) @@ -39,36 +38,16 @@ } \ } -namespace curry { namespace vwr { SPECIALIZE_ARRAY_VECTOR(float, 2); SPECIALIZE_ARRAY_VECTOR(uint16_t, 2); SPECIALIZE_ARRAY_VECTOR(int32_t, 2); - template <> - struct VectorWrapperInfo { - enum { dimensions = 2 }; - typedef cloonel::ushort2::scalar_type scalar_type; - typedef cloonel::ushort2 vector_type; - static scalar_type& get_at (size_type parIndex, vector_type& parVector) { - return parVector[parIndex]; - } - }; - template <> - struct VectorWrapperInfo { - enum { dimensions = 2 }; - typedef cloonel::float2::scalar_type scalar_type; - typedef cloonel::float2 vector_type; - static scalar_type& get_at (size_type parIndex, vector_type& parVector) { - return parVector[parIndex]; - } - }; - #if !defined(NDEBUG) template std::ostream& operator<< (std::ostream& parStream, const Vec& parVec) { parStream << '<'; - for (size_type z = 0; z < Vec::dimensions - 1; ++z) { + for (std::size_t z = 0; z < Vec::dimensions - 1; ++z) { std::cout << parVec[z] << ", "; } std::cout << parVec[Vec::dimensions - 1] << '>'; @@ -96,14 +75,18 @@ namespace vwr { return implem::vector_cast(parVec, to, std::make_index_sequence::dimensions>()); } } //namespace vwr -} //namespace curry namespace curry { using vec2f = vwr::Vec>; using vec2us = vwr::Vec>; using vec2i = vwr::Vec>; - using cl_vec2us = vwr::Vec; using vwr::vector_cast; } //namespace curry +//make stuff from CloonelJump compile happily +namespace cloonel { + using ushort2 = vwr::Vec>; + using float2 = vwr::Vec>; +} //namespace cloonel + #undef SPECIALIZE_ARRAY_VECTOR diff --git a/src/gamelib/worldgrid.cpp b/src/worldgrid.cpp similarity index 82% rename from src/gamelib/worldgrid.cpp rename to src/worldgrid.cpp index 83f7362..6e845c8 100644 --- a/src/gamelib/worldgrid.cpp +++ b/src/worldgrid.cpp @@ -118,33 +118,15 @@ namespace curry { m_world_size_watchers.Remove(parTicket); } - void WorldGrid::set_tile_properties (const std::vector& parProperties) { - m_tile_properties.resize(parProperties.size()); - std::copy(parProperties.begin(), parProperties.end(), m_tile_properties.begin()); - } - - const TileProperty& WorldGrid::tile_property (const TileIndex* parIndex) const { - assert(parIndex); - assert(static_cast(*parIndex) < m_tile_properties.size()); - return m_tile_properties[static_cast(*parIndex)]; - } - vec2i world_size_pixel (const WorldGrid& parWorld) { return parWorld.tile_size() * parWorld.world_size(); } - vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2f& parPos) { + vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2i& parPos) { assert(position_is_on_map(parWorld, parPos)); - const auto retval = vector_cast( - parPos / vector_cast(parWorld.tile_size()) + return vector_cast( + parPos / vector_cast(parWorld.tile_size()) ); - assert(world_tile_to_pixel(parWorld, retval) <= parPos); - return retval; - } - - vec2f world_tile_to_pixel (const WorldGrid& parWorld, const vec2us& parTile) { - assert(parTile < parWorld.world_size()); - return vector_cast(parTile) * vector_cast(parWorld.tile_size()); } bool position_is_on_map (const WorldGrid& parWorld, const vec2i& parPos) { diff --git a/src/gamelib/worldgrid.hpp b/src/worldgrid.hpp similarity index 86% rename from src/gamelib/worldgrid.hpp rename to src/worldgrid.hpp index 7f2b5f4..1dd94af 100644 --- a/src/gamelib/worldgrid.hpp +++ b/src/worldgrid.hpp @@ -22,7 +22,6 @@ #include "vector.hpp" #include "tileindextype.hpp" #include "observersmanager.hpp" -#include "tileproperty.hpp" #include #include @@ -41,8 +40,6 @@ namespace curry { const TileIndex* tile (const vec2us& parIndex) const; void add_layer (vec2us parWorldSize, const std::vector& parLayer); void set_layers (vec2us parWorldSize, const std::vector>& parLayers); - void set_tile_properties (const std::vector& parProperties); - const TileProperty& tile_property (const TileIndex* parIndex) const; void unload_layers(); WorldSizeWatcherTicket register_observer (WorldSizeNotifiable* parWatcher); void unregister_observer (WorldSizeWatcherTicket parTicket); @@ -54,14 +51,12 @@ namespace curry { cloonel::ObserversManager m_world_size_watchers; std::vector m_layers; - std::vector m_tile_properties; vec2us m_tile_size; vec2us m_world_size; uint16_t m_layer_count; }; vec2i world_size_pixel (const WorldGrid& parWorld); - vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2f& parPos); - vec2f world_tile_to_pixel (const WorldGrid& parWorld, const vec2us& parTile); + vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2i& parPos); bool position_is_on_map (const WorldGrid& parWorld, const vec2i& parPos); } //namespace curry diff --git a/src/gamelib/worlditems.cpp b/src/worlditems.cpp similarity index 100% rename from src/gamelib/worlditems.cpp rename to src/worlditems.cpp diff --git a/src/gamelib/worlditems.hpp b/src/worlditems.hpp similarity index 100% rename from src/gamelib/worlditems.hpp rename to src/worlditems.hpp diff --git a/src/gamelib/worldsizenotifiable.cpp b/src/worldsizenotifiable.cpp similarity index 100% rename from src/gamelib/worldsizenotifiable.cpp rename to src/worldsizenotifiable.cpp diff --git a/src/gamelib/worldsizenotifiable.hpp b/src/worldsizenotifiable.hpp similarity index 100% rename from src/gamelib/worldsizenotifiable.hpp rename to src/worldsizenotifiable.hpp diff --git a/src/gamelib/worldviewport.cpp b/src/worldviewport.cpp similarity index 100% rename from src/gamelib/worldviewport.cpp rename to src/worldviewport.cpp diff --git a/src/gamelib/worldviewport.hpp b/src/worldviewport.hpp similarity index 100% rename from src/gamelib/worldviewport.hpp rename to src/worldviewport.hpp diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt deleted file mode 100644 index 4e3d6bf..0000000 --- a/test/unit/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -project(mycurry_unit_test CXX) - -add_executable(${PROJECT_NAME} - main.cpp - grid_raytrace.cpp -) -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14) -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) - -target_compile_definitions(${PROJECT_NAME} - PRIVATE VWR_WITH_IMPLICIT_CONVERSIONS=1 - PRIVATE VWR_EXTRA_ACCESSORS -) - -target_include_directories(${PROJECT_NAME} - PRIVATE ${CATCH_SOURCE_DIR}/single_include - PRIVATE ${CMAKE_SOURCE_DIR}/src/gamelib - PRIVATE ${CMAKE_SOURCE_DIR}/lib/vectorwrapper/include - PRIVATE ${CMAKE_SOURCE_DIR}/lib/tree-2.81/src - PRIVATE ${CMAKE_BINARY_DIR} -) - -add_test( - NAME CloonelJumpTest - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${PROJECT_NAME} -) - -target_link_libraries(${PROJECT_NAME} - PRIVATE mycurry_gamelib -) diff --git a/test/unit/grid_raytrace.cpp b/test/unit/grid_raytrace.cpp deleted file mode 100644 index cae8b5c..0000000 --- a/test/unit/grid_raytrace.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#include "catch.hpp" -#include "grid_raytrace.hpp" -#include "worldgrid.hpp" -#include "tileindextype.hpp" -#include "tileproperty.hpp" -#include - -TEST_CASE ("Check that 2D raytracing works", "[raytracing][geometry]") { - using curry::for_each_cell_under_segment; - using curry::vec2us; - using curry::vec2f; - - curry::WorldGrid world(vec2us(64)); - world.set_layers(vec2us(10, 10), std::vector>( {{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }})); - world.set_tile_properties(std::vector({ curry::TileProperty() })); - - REQUIRE(world.world_size() == vec2us(10)); - REQUIRE(world.layer_count() == 1); - - { - std::vector diagonal; - for_each_cell_under_segment ( - vec2f(0.0f, 0.0f), //from - vec2f(639.0f, 639.0f), //to - vec2us(1, 1), //objsize - world, //world - [&diagonal](vec2us wtp) mutable {diagonal.push_back(wtp); return true;}, - true - ); - - const auto* tile_prop = &world.tile_property(world.tile(vec2us(0))); - std::vector expected { - vec2us(0, 0), vec2us(0, 1), - vec2us(1, 1), vec2us(1, 2), - vec2us(2, 2), vec2us(2, 3), - vec2us(3, 3), vec2us(3, 4), - vec2us(4, 4), vec2us(4, 5), - vec2us(5, 5), vec2us(5, 6), - vec2us(6, 6), vec2us(6, 7), - vec2us(7, 7), vec2us(7, 8), - vec2us(8, 8), vec2us(8, 9), - vec2us(9, 9) - }; - CHECK(expected == diagonal); - } -} - -TEST_CASE ("Check that segment intersection code used by the raytracing code works", "[geometry][intersection]") { - using curry::vec2f; - using curry::segment_intersection; - - { - //Two segments crossing at <0, 0> - const vec2f a0(-1.0f, 0.0f); - const vec2f a1(2.0f, 0.0f); - const vec2f b0(0.0f, 1.0f); - const vec2f b1(0.0f, -2.0f); - - const float t1 = segment_intersection(a0, a1, b0, b1); - CHECK(0.5f == t1); - CHECK(vec2f(0.0f) == a0 + t1 * a1); - const float t2 = segment_intersection(b0, b1, a0, a1); - CHECK(0.5f == t2); - } - - { - //a diagonal segment starting off from a vertical segment - const vec2f a0(-1.0f, 0.0f); - const vec2f a1(3.0f, 2.0f); - const vec2f b0(-1.0f, 1.0f); - const vec2f b1(0.0f, -2.0f); - - const float t1 = segment_intersection(a0, a1, b0, b1); - CHECK(0.0f == t1); - const float t2 = segment_intersection(b0, b1, a0, a1); - CHECK(0.5f == t2); - } -} diff --git a/test/unit/main.cpp b/test/unit/main.cpp deleted file mode 100644 index a35d71c..0000000 --- a/test/unit/main.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - Copyright 2016, 2017 Michele "King_DuckZ" Santullo - - This file is part of MyCurry. - - MyCurry is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - MyCurry is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with MyCurry. If not, see . -*/ - -#define CATCH_CONFIG_MAIN -#include "catch.hpp"