diff --git a/.gitmodules b/.gitmodules index 070d332..0c3e3cf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,15 @@ [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 cd07e60..f9d2048 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,17 @@ cmake_minimum_required(VERSION 3.2) -project(mycurry CXX) +project(mycurry_toplevel CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/include") include(TargetArch) include(FindPkgConfig) - -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}") +include(CTest) 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}") @@ -34,9 +30,6 @@ 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) @@ -51,71 +44,33 @@ 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) -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 -) +configure_file(src/${PROJECT_NAME}Config.h.in ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.h) +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} - PRIVATE ${PNG_DEFINITIONS} - PRIVATE VWR_WITH_IMPLICIT_CONVERSIONS=1 - PRIVATE VWR_EXTRA_ACCESSORS + INTERFACE $<$:KAK_DEBUG> + INTERFACE VWR_OUTER_NAMESPACE=curry +) +target_include_directories(${PROJECT_NAME} + INTERFACE lib/kakoune + INTERFACE lib/better-enums ) -configure_file(src/${PROJECT_NAME}Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.h) +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() diff --git a/docs/assembly_references.txt b/docs/assembly_references.txt new file mode 100644 index 0000000..5f06673 --- /dev/null +++ b/docs/assembly_references.txt @@ -0,0 +1,26 @@ +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 new file mode 100644 index 0000000..ba827a0 --- /dev/null +++ b/docs/old_code/asm/x86_64/fsgn.s @@ -0,0 +1,48 @@ +# +# 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 new file mode 100644 index 0000000..1a1886f --- /dev/null +++ b/docs/old_code/fsgn_timing.cpp @@ -0,0 +1,83 @@ +/* + 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/src/singlecoordinate.cpp b/docs/old_code/fsgn_timing.hpp similarity index 78% rename from src/singlecoordinate.cpp rename to docs/old_code/fsgn_timing.hpp index 781d3dc..7843658 100644 --- a/src/singlecoordinate.cpp +++ b/docs/old_code/fsgn_timing.hpp @@ -17,10 +17,12 @@ along with MyCurry. If not, see . */ -#include "singlecoordinate.hpp" -#include "coordinates.hpp" +#pragma once + +#define FSGN_WITH_TIMING namespace curry { - static_assert(implem::Log2<256>::result == 8, "Wrong logarithm result"); - static_assert(implem::Log2<255>::result == 7, "Wrong logarithm result"); +#if defined(FSGN_WITH_TIMING) + void do_fsgn_timing(); +#endif } //namespace curry diff --git a/gdb/vectorwrapper.py b/gdb/vectorwrapper.py new file mode 100644 index 0000000..1db58a6 --- /dev/null +++ b/gdb/vectorwrapper.py @@ -0,0 +1,72 @@ + # + # 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 new file mode 100644 index 0000000..36aa80d --- /dev/null +++ b/lib/kakoune/safe_ptr.hh @@ -0,0 +1,109 @@ +#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 new file mode 160000 index 0000000..3934199 --- /dev/null +++ b/lib/tmxlite @@ -0,0 +1 @@ +Subproject commit 3934199e22d68a3a1e7c72049b5f6e85559e99dc diff --git a/lib/tree-2.81/ChangeLog b/lib/tree-2.81/ChangeLog deleted file mode 100644 index 9b05100..0000000 --- a/lib/tree-2.81/ChangeLog +++ /dev/null @@ -1,391 +0,0 @@ -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 deleted file mode 100644 index ee30472..0000000 --- a/lib/tree-2.81/Makefile +++ /dev/null @@ -1,27 +0,0 @@ - -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 deleted file mode 100644 index 59d3226..0000000 --- a/lib/tree-2.81/doc/documentation.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - -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 deleted file mode 100644 index 4bb45a7..0000000 --- a/lib/tree-2.81/doc/download.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - -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 deleted file mode 100644 index 5095e07..0000000 --- a/lib/tree-2.81/doc/doxygen_tree.config +++ /dev/null @@ -1,270 +0,0 @@ -# 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 deleted file mode 100644 index 4eb6ffe..0000000 Binary files a/lib/tree-2.81/doc/favicon.ico and /dev/null differ diff --git a/lib/tree-2.81/doc/favicon.png b/lib/tree-2.81/doc/favicon.png deleted file mode 100644 index 69d16b3..0000000 Binary files a/lib/tree-2.81/doc/favicon.png and /dev/null differ diff --git a/lib/tree-2.81/doc/filler.png b/lib/tree-2.81/doc/filler.png deleted file mode 100644 index 548e1e4..0000000 Binary files a/lib/tree-2.81/doc/filler.png and /dev/null differ diff --git a/lib/tree-2.81/doc/index.html b/lib/tree-2.81/doc/index.html deleted file mode 100644 index f807fa2..0000000 --- a/lib/tree-2.81/doc/index.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - -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 deleted file mode 100644 index 03af4d5..0000000 --- a/lib/tree-2.81/doc/projects.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - -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 deleted file mode 100644 index fbad024..0000000 Binary files a/lib/tree-2.81/doc/structure.png and /dev/null differ diff --git a/lib/tree-2.81/doc/structure.svg b/lib/tree-2.81/doc/structure.svg deleted file mode 100644 index 8a2bf21..0000000 --- a/lib/tree-2.81/doc/structure.svg +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - - - - - 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 deleted file mode 100644 index 03b84c8..0000000 --- a/lib/tree-2.81/doc/tree.css +++ /dev/null @@ -1,171 +0,0 @@ - -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 deleted file mode 100644 index d6f58f7..0000000 Binary files a/lib/tree-2.81/doc/tree.jpg and /dev/null differ diff --git a/lib/tree-2.81/doc/tree.png b/lib/tree-2.81/doc/tree.png deleted file mode 100644 index 04fa420..0000000 Binary files a/lib/tree-2.81/doc/tree.png and /dev/null differ diff --git a/lib/tree-2.81/doc/tree.tex b/lib/tree-2.81/doc/tree.tex deleted file mode 100644 index 4ba233d..0000000 --- a/lib/tree-2.81/doc/tree.tex +++ /dev/null @@ -1,388 +0,0 @@ -\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 deleted file mode 100644 index 9dd31b0..0000000 Binary files a/lib/tree-2.81/doc/tree2.png and /dev/null differ diff --git a/lib/tree-2.81/doc/treefig.eps b/lib/tree-2.81/doc/treefig.eps deleted file mode 100644 index c813732..0000000 --- a/lib/tree-2.81/doc/treefig.eps +++ /dev/null @@ -1,190 +0,0 @@ -%!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 deleted file mode 100644 index f506563..0000000 --- a/lib/tree-2.81/doc/treefig.fig +++ /dev/null @@ -1,44 +0,0 @@ -#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 deleted file mode 100644 index 547b9e4..0000000 --- a/lib/tree-2.81/doc/treefig.pdf +++ /dev/null @@ -1,71 +0,0 @@ -%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 deleted file mode 100644 index f0ef4c3..0000000 --- a/lib/tree-2.81/src/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.o -*.res -test1 diff --git a/lib/tree-2.81/src/Makefile b/lib/tree-2.81/src/Makefile deleted file mode 100644 index 7d1aba7..0000000 --- a/lib/tree-2.81/src/Makefile +++ /dev/null @@ -1,14 +0,0 @@ - -%.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 deleted file mode 100644 index 5c7b54c..0000000 --- a/lib/tree-2.81/src/simple tree.hpp +++ /dev/null @@ -1,1560 +0,0 @@ -// 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 deleted file mode 100644 index 5bb2fdf..0000000 --- a/lib/tree-2.81/src/test1.cc +++ /dev/null @@ -1,18 +0,0 @@ -#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 deleted file mode 100644 index e2e3a45..0000000 --- a/lib/tree-2.81/src/test1.req +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 6f1bf1c..0000000 --- a/lib/tree-2.81/src/test_tree.cc +++ /dev/null @@ -1,378 +0,0 @@ -/* - - 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 deleted file mode 100644 index f6b0848..0000000 --- a/lib/tree-2.81/src/test_tree.output +++ /dev/null @@ -1,311 +0,0 @@ -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 deleted file mode 100644 index b2f3005..0000000 --- a/lib/tree-2.81/src/tree.hh +++ /dev/null @@ -1,2786 +0,0 @@ - -// 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 deleted file mode 100644 index d351f51..0000000 --- a/lib/tree-2.81/src/tree_example.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - - 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 deleted file mode 100644 index f8db036..0000000 --- a/lib/tree-2.81/src/xinlin.hh +++ /dev/null @@ -1,1579 +0,0 @@ -// 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 fc7b666..50ebba1 160000 --- a/lib/vectorwrapper +++ b/lib/vectorwrapper @@ -1 +1 @@ -Subproject commit fc7b66642959e7de19aade010b6ebc1e59ba4b7a +Subproject commit 50ebba1c3157196d142bc06ebf2d290c7702b084 diff --git a/nonfree_map.tmx b/nonfree_map.tmx index 3124404..386e532 100644 --- a/nonfree_map.tmx +++ b/nonfree_map.tmx @@ -2,6 +2,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/coordinates.hpp b/src/coordinates.hpp deleted file mode 100644 index d4d0b7a..0000000 --- a/src/coordinates.hpp +++ /dev/null @@ -1,53 +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 "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/CMakeLists.txt b/src/gamelib/CMakeLists.txt new file mode 100644 index 0000000..140d7aa --- /dev/null +++ b/src/gamelib/CMakeLists.txt @@ -0,0 +1,52 @@ +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/character.cpp b/src/gamelib/character.cpp similarity index 59% rename from src/character.cpp rename to src/gamelib/character.cpp index 971e4f9..2e75122 100644 --- a/src/character.cpp +++ b/src/gamelib/character.cpp @@ -21,58 +21,27 @@ #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) : - WorldSizeNotifiable(parDeferredRegister), - m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f)), - m_width_height(0.0f), + WorldMoveable(parDeferredRegister), 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( - m_position.get() - parWorldPos, - m_position.get() - parWorldPos + width_height() + position() - parWorldPos, + position() - parWorldPos + width_height() ); } @@ -83,10 +52,6 @@ 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); @@ -100,10 +65,18 @@ namespace curry { offset.y() += speed; const auto old_pos = this->position(); - const auto new_pos = old_pos + offset; + this->set_position(old_pos + offset); + if (position() == old_pos) + return; - //if (m_world + WorldGrid& world = this->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); } @@ -111,4 +84,17 @@ 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/character.hpp b/src/gamelib/character.hpp similarity index 68% rename from src/character.hpp rename to src/gamelib/character.hpp index 008410a..796e62e 100644 --- a/src/character.hpp +++ b/src/gamelib/character.hpp @@ -19,12 +19,11 @@ #pragma once -#include "texture.hpp" #include "vector.hpp" #include "rect.hpp" -#include "constrained_position.hpp" -#include "worldsizenotifiable.hpp" -#include "moveable.hpp" +#include "world_moveable.hpp" +#include "drawable.hpp" +#include "collider.hpp" namespace cloonel { class SDLMain; @@ -34,29 +33,22 @@ namespace cloonel { namespace curry { class WorldGrid; - class Character : public WorldSizeNotifiable, public Moveable { + class Character : public Drawable, public WorldMoveable { 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: - ConstrainedPosition m_position; - Texture m_texture; - vec2f m_width_height; + virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz) override; + cloonel::InputBag* m_input_bag; - WorldGrid* m_world; + Collider m_collider; float m_speed; }; } //namespace curry diff --git a/src/gamelib/collider.cpp b/src/gamelib/collider.cpp new file mode 100644 index 0000000..4cfd314 --- /dev/null +++ b/src/gamelib/collider.cpp @@ -0,0 +1,109 @@ +/* + 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 new file mode 100644 index 0000000..d7d5814 --- /dev/null +++ b/src/gamelib/collider.hpp @@ -0,0 +1,43 @@ +/* + 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/compatibility.h b/src/gamelib/compatibility.h similarity index 100% rename from src/compatibility.h rename to src/gamelib/compatibility.h diff --git a/src/constrained_position.hpp b/src/gamelib/constrained_position.hpp similarity index 100% rename from src/constrained_position.hpp rename to src/gamelib/constrained_position.hpp diff --git a/src/constrained_value.hpp b/src/gamelib/constrained_value.hpp similarity index 100% rename from src/constrained_value.hpp rename to src/gamelib/constrained_value.hpp diff --git a/src/csvloader.cpp b/src/gamelib/csvloader.cpp similarity index 81% rename from src/csvloader.cpp rename to src/gamelib/csvloader.cpp index ceb9a78..c3c732f 100644 --- a/src/csvloader.cpp +++ b/src/gamelib/csvloader.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace qi = boost::spirit::qi; @@ -47,6 +48,7 @@ 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); @@ -66,6 +68,9 @@ 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)); } @@ -76,6 +81,18 @@ 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/csvloader.hpp b/src/gamelib/csvloader.hpp similarity index 91% rename from src/csvloader.hpp rename to src/gamelib/csvloader.hpp index 587e9cb..ce3672d 100644 --- a/src/csvloader.hpp +++ b/src/gamelib/csvloader.hpp @@ -20,6 +20,7 @@ #pragma once #include "tileindextype.hpp" +#include "tileproperty.hpp" #include #include #include @@ -31,6 +32,7 @@ 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/draw_layer_names.hpp b/src/gamelib/draw_layer_names.hpp new file mode 100644 index 0000000..0065075 --- /dev/null +++ b/src/gamelib/draw_layer_names.hpp @@ -0,0 +1,38 @@ +/* + 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 new file mode 100644 index 0000000..7032e3b --- /dev/null +++ b/src/gamelib/drawable.cpp @@ -0,0 +1,91 @@ +/* + 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 new file mode 100644 index 0000000..a312b02 --- /dev/null +++ b/src/gamelib/drawable.hpp @@ -0,0 +1,56 @@ +/* + 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/gamescenebase.cpp b/src/gamelib/drawing_queue.cpp similarity index 55% rename from src/gamescenebase.cpp rename to src/gamelib/drawing_queue.cpp index 620f0f2..449c157 100644 --- a/src/gamescenebase.cpp +++ b/src/gamelib/drawing_queue.cpp @@ -17,23 +17,25 @@ along with MyCurry. If not, see . */ -#include "gamescenebase.hpp" -#include "inputbag.hpp" +#include "drawing_queue.hpp" #include "sdlmain.hpp" +#include "sizeratio.hpp" #include "rect_to_sdl.hpp" -#include "rect.hpp" #include "texture.hpp" -#include #include -#include +#include #include -#if !defined(NDEBUG) -# include "compatibility.h" -# include -#endif +#include +#include +#include +#include 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; @@ -43,39 +45,6 @@ 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. @@ -125,70 +94,85 @@ namespace curry { } } //unnamed namespace - 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) + 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)) { - assert(m_sdlmain); + assert(parSDLMain); } - GameSceneBase::~GameSceneBase() noexcept = default; + DrawingQueue::~DrawingQueue() noexcept = default; - void GameSceneBase::prepare() { - m_wants_to_quit = false; - this->on_prepare(); - - m_time0 = std::chrono::steady_clock::now(); + 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::destroy() noexcept { - set_wants_to_quit(); - this->on_destroy(); + 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(); + } } - bool GameSceneBase::wants_to_quit() const { - return m_wants_to_quit; + 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()); } - 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) { + void DrawingQueue::draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest) { const vec2f lefttop(0.0f); - const vec2f rightbottom(m_screen_width, m_screen_height); + const vec2f& rightbottom = m_local_data->screen_res; 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_sdlmain->GetRenderer(), parTexture.texture(), &src, &dst); + 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())); } } //namespace curry diff --git a/src/gamelib/drawing_queue.hpp b/src/gamelib/drawing_queue.hpp new file mode 100644 index 0000000..32f5cf3 --- /dev/null +++ b/src/gamelib/drawing_queue.hpp @@ -0,0 +1,70 @@ +/* + 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/gameactions.hpp b/src/gamelib/gameactions.hpp similarity index 100% rename from src/gameactions.hpp rename to src/gamelib/gameactions.hpp diff --git a/src/gamelib/gamescenebase.cpp b/src/gamelib/gamescenebase.cpp new file mode 100644 index 0000000..7d01b2a --- /dev/null +++ b/src/gamelib/gamescenebase.cpp @@ -0,0 +1,135 @@ +/* + 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/gamescenebase.hpp b/src/gamelib/gamescenebase.hpp similarity index 91% rename from src/gamescenebase.hpp rename to src/gamelib/gamescenebase.hpp index f5e072f..d92599f 100644 --- a/src/gamescenebase.hpp +++ b/src/gamelib/gamescenebase.hpp @@ -28,8 +28,8 @@ namespace cloonel { } //namespace cloonel namespace curry { - class Texture; template class Rect; + class DrawingQueue; class GameSceneBase { public: @@ -50,11 +50,13 @@ namespace curry { virtual void on_update (float parDeltaT) = 0; cloonel::SDLMain* sdl_main(); cloonel::InputBag& input_bag(); - void draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest); + DrawingQueue& drawing_queue(); + const DrawingQueue& drawing_queue() const; 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/grid_raytrace.cpp b/src/gamelib/grid_raytrace.cpp new file mode 100644 index 0000000..0fbee0e --- /dev/null +++ b/src/gamelib/grid_raytrace.cpp @@ -0,0 +1,169 @@ +/* + 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 new file mode 100644 index 0000000..c264efa --- /dev/null +++ b/src/gamelib/grid_raytrace.hpp @@ -0,0 +1,41 @@ +/* + 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/ingamescene.cpp b/src/gamelib/ingamescene.cpp similarity index 70% rename from src/ingamescene.cpp rename to src/gamelib/ingamescene.cpp index d2a15cd..d7bfdfa 100644 --- a/src/ingamescene.cpp +++ b/src/gamelib/ingamescene.cpp @@ -19,7 +19,7 @@ #include "ingamescene.hpp" #include "sdlmain.hpp" -#include "mycurryConfig.h" +#include "mycurry_toplevelConfig.h" #include "key.hpp" #include "inputbag.hpp" #include "movingobject.hpp" @@ -31,6 +31,9 @@ #include "csvloader.hpp" #include "worlditems.hpp" #include "gameactions.hpp" +#include "vector.hpp" +#include "drawing_queue.hpp" +#include "safe_stack_object.hpp" #include #include #include @@ -38,15 +41,21 @@ #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(parSDLMain->WidthHeight()), WorldSizeNotifiable::DeferredRegister(&world, &viewport)), + viewport(&world, vec2f(cl_vec2us(parSDLMain->WidthHeight())), WorldSizeNotifiable::DeferredRegister(&world, &viewport)), player(parTileSize), character(parInputBag, WorldSizeNotifiable::DeferredRegister(&world, &character)) { @@ -54,7 +63,7 @@ namespace curry { WorldGrid world; WorldViewport viewport; - Texture worldtiles; + SafeStackObject worldtiles; MovingObject player; Character character; WorldItems moveable_items; @@ -72,12 +81,18 @@ 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" @@ -85,12 +100,13 @@ 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.load(RESOURCES_PATH "LPC_Sara_Preview.png", *this->sdl_main()); + m_local_data->character.add_texture(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()) @@ -108,8 +124,9 @@ 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) @@ -120,15 +137,24 @@ namespace curry { Rect src_rect(src_rect_xy, src_rect_xy + tilesize); Rect dst_rect(pixel_pos, pixel_pos + tilesize); - this->draw_clipped(m_local_data->worldtiles, src_rect, dst_rect); + this->draw(DrawaLayerNames::Background, m_local_data->worldtiles, src_rect, dst_rect); } } - this->draw_clipped(m_local_data->character.texture(), m_local_data->character.source_rect(), m_local_data->character.destination_rect(viewport.position())); + m_local_data->character.draw(drawing_queue(), viewport); } void IngameScene::on_destroy() noexcept { m_local_data->moveable_items.unregister_all(); - m_local_data->worldtiles.unload(); - m_local_data->character.unload(); + 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); } } //namespace curry diff --git a/src/ingamescene.hpp b/src/gamelib/ingamescene.hpp similarity index 85% rename from src/ingamescene.hpp rename to src/gamelib/ingamescene.hpp index 55c8900..7ff398c 100644 --- a/src/ingamescene.hpp +++ b/src/gamelib/ingamescene.hpp @@ -20,13 +20,18 @@ #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); @@ -36,6 +41,7 @@ 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/moveable.cpp b/src/gamelib/moveable.cpp similarity index 100% rename from src/moveable.cpp rename to src/gamelib/moveable.cpp diff --git a/src/moveable.hpp b/src/gamelib/moveable.hpp similarity index 100% rename from src/moveable.hpp rename to src/gamelib/moveable.hpp diff --git a/src/movingobject.cpp b/src/gamelib/movingobject.cpp similarity index 100% rename from src/movingobject.cpp rename to src/gamelib/movingobject.cpp diff --git a/src/movingobject.hpp b/src/gamelib/movingobject.hpp similarity index 100% rename from src/movingobject.hpp rename to src/gamelib/movingobject.hpp diff --git a/src/rect.hpp b/src/gamelib/rect.hpp similarity index 100% rename from src/rect.hpp rename to src/gamelib/rect.hpp diff --git a/src/rect_to_sdl.cpp b/src/gamelib/rect_to_sdl.cpp similarity index 100% rename from src/rect_to_sdl.cpp rename to src/gamelib/rect_to_sdl.cpp diff --git a/src/rect_to_sdl.hpp b/src/gamelib/rect_to_sdl.hpp similarity index 100% rename from src/rect_to_sdl.hpp rename to src/gamelib/rect_to_sdl.hpp diff --git a/src/gamelib/safe_stack_object.hpp b/src/gamelib/safe_stack_object.hpp new file mode 100644 index 0000000..f9e0439 --- /dev/null +++ b/src/gamelib/safe_stack_object.hpp @@ -0,0 +1,87 @@ +/* + 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/texture.cpp b/src/gamelib/texture.cpp similarity index 86% rename from src/texture.cpp rename to src/gamelib/texture.cpp index 2eba3ea..8e164b4 100644 --- a/src/texture.cpp +++ b/src/gamelib/texture.cpp @@ -73,6 +73,20 @@ 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/texture.hpp b/src/gamelib/texture.hpp similarity index 86% rename from src/texture.hpp rename to src/gamelib/texture.hpp index f6a2003..12ab27c 100644 --- a/src/texture.hpp +++ b/src/gamelib/texture.hpp @@ -20,6 +20,7 @@ #pragma once #include "vector.hpp" +#include "safe_ptr.hh" #include #include @@ -37,14 +38,17 @@ namespace curry { uint8_t a; }; - class Texture { + class Texture : public Kakoune::SafeCountable { 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/tileindextype.hpp b/src/gamelib/tileindextype.hpp similarity index 100% rename from src/tileindextype.hpp rename to src/gamelib/tileindextype.hpp diff --git a/src/tileiterator.cpp b/src/gamelib/tileiterator.cpp similarity index 100% rename from src/tileiterator.cpp rename to src/gamelib/tileiterator.cpp diff --git a/src/tileiterator.hpp b/src/gamelib/tileiterator.hpp similarity index 100% rename from src/tileiterator.hpp rename to src/gamelib/tileiterator.hpp diff --git a/src/gamelib/tileproperty.hpp b/src/gamelib/tileproperty.hpp new file mode 100644 index 0000000..35717fa --- /dev/null +++ b/src/gamelib/tileproperty.hpp @@ -0,0 +1,31 @@ +/* + 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 + +namespace curry { + struct TileProperty { + TileProperty() : + walkable(true) + { + } + + bool walkable; + }; +} //namespace curry diff --git a/src/vector.hpp b/src/gamelib/vector.hpp similarity index 77% rename from src/vector.hpp rename to src/gamelib/vector.hpp index 2546b94..34c2221 100644 --- a/src/vector.hpp +++ b/src/gamelib/vector.hpp @@ -20,6 +20,7 @@ #pragma once #include "vectorwrapper/vectorwrapper.hpp" +#include "vectypes.hpp" #include #include #if !defined(NDEBUG) @@ -38,16 +39,36 @@ } \ } +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 (std::size_t z = 0; z < Vec::dimensions - 1; ++z) { + for (size_type z = 0; z < Vec::dimensions - 1; ++z) { std::cout << parVec[z] << ", "; } std::cout << parVec[Vec::dimensions - 1] << '>'; @@ -75,18 +96,14 @@ 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/world_moveable.cpp b/src/gamelib/world_moveable.cpp new file mode 100644 index 0000000..2e20957 --- /dev/null +++ b/src/gamelib/world_moveable.cpp @@ -0,0 +1,57 @@ +/* + 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 new file mode 100644 index 0000000..ec6492f --- /dev/null +++ b/src/gamelib/world_moveable.hpp @@ -0,0 +1,47 @@ +/* + 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/worldgrid.cpp b/src/gamelib/worldgrid.cpp similarity index 82% rename from src/worldgrid.cpp rename to src/gamelib/worldgrid.cpp index 6e845c8..83f7362 100644 --- a/src/worldgrid.cpp +++ b/src/gamelib/worldgrid.cpp @@ -118,15 +118,33 @@ 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 vec2i& parPos) { + vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2f& parPos) { assert(position_is_on_map(parWorld, parPos)); - return vector_cast( - parPos / vector_cast(parWorld.tile_size()) + const auto retval = 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/worldgrid.hpp b/src/gamelib/worldgrid.hpp similarity index 86% rename from src/worldgrid.hpp rename to src/gamelib/worldgrid.hpp index 1dd94af..7f2b5f4 100644 --- a/src/worldgrid.hpp +++ b/src/gamelib/worldgrid.hpp @@ -22,6 +22,7 @@ #include "vector.hpp" #include "tileindextype.hpp" #include "observersmanager.hpp" +#include "tileproperty.hpp" #include #include @@ -40,6 +41,8 @@ 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); @@ -51,12 +54,14 @@ 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 vec2i& parPos); + vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2f& parPos); + vec2f world_tile_to_pixel (const WorldGrid& parWorld, const vec2us& parTile); bool position_is_on_map (const WorldGrid& parWorld, const vec2i& parPos); } //namespace curry diff --git a/src/worlditems.cpp b/src/gamelib/worlditems.cpp similarity index 100% rename from src/worlditems.cpp rename to src/gamelib/worlditems.cpp diff --git a/src/worlditems.hpp b/src/gamelib/worlditems.hpp similarity index 100% rename from src/worlditems.hpp rename to src/gamelib/worlditems.hpp diff --git a/src/worldsizenotifiable.cpp b/src/gamelib/worldsizenotifiable.cpp similarity index 100% rename from src/worldsizenotifiable.cpp rename to src/gamelib/worldsizenotifiable.cpp diff --git a/src/worldsizenotifiable.hpp b/src/gamelib/worldsizenotifiable.hpp similarity index 100% rename from src/worldsizenotifiable.hpp rename to src/gamelib/worldsizenotifiable.hpp diff --git a/src/worldviewport.cpp b/src/gamelib/worldviewport.cpp similarity index 100% rename from src/worldviewport.cpp rename to src/gamelib/worldviewport.cpp diff --git a/src/worldviewport.hpp b/src/gamelib/worldviewport.hpp similarity index 100% rename from src/worldviewport.hpp rename to src/gamelib/worldviewport.hpp diff --git a/src/inputbag.cpp b/src/inputbag.cpp deleted file mode 100644 index e63b5b4..0000000 --- a/src/inputbag.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - 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 deleted file mode 100644 index 3b96040..0000000 --- a/src/inputbag.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - 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 deleted file mode 100644 index 3058e38..0000000 --- a/src/inputdevicetype.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - 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 deleted file mode 100644 index bd25baf..0000000 --- a/src/key.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - 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/mycurryConfig.h.in b/src/mycurry_toplevelConfig.h.in similarity index 96% rename from src/mycurryConfig.h.in rename to src/mycurry_toplevelConfig.h.in index 165dab5..ac6f3c4 100644 --- a/src/mycurryConfig.h.in +++ b/src/mycurry_toplevelConfig.h.in @@ -20,3 +20,4 @@ #pragma once #define RESOURCES_PATH "@MYCURRY_RESOURCES_PATH@/" +#cmakedefine BUILD_TESTING diff --git a/src/observersmanager.hpp b/src/observersmanager.hpp deleted file mode 100644 index 926c532..0000000 --- a/src/observersmanager.hpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - 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/sdlmain.cpp b/src/sdlmain.cpp deleted file mode 100644 index 2d0d9df..0000000 --- a/src/sdlmain.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - 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 deleted file mode 100644 index dc05b8c..0000000 --- a/src/sdlmain.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - 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/singlecoordinate.hpp b/src/singlecoordinate.hpp deleted file mode 100644 index 2ca9460..0000000 --- a/src/singlecoordinate.hpp +++ /dev/null @@ -1,110 +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 -#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 deleted file mode 100644 index 7d6750d..0000000 --- a/src/sizenotifiable.cpp +++ /dev/null @@ -1,78 +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 "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 deleted file mode 100644 index 132cf34..0000000 --- a/src/sizenotifiable.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - 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 deleted file mode 100644 index 53a7af7..0000000 --- a/src/sizeratio.cpp +++ /dev/null @@ -1,66 +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 "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 deleted file mode 100644 index 6e0cc4f..0000000 --- a/src/sizeratio.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - 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 new file mode 100644 index 0000000..a44913f --- /dev/null +++ b/src/standalone/CMakeLists.txt @@ -0,0 +1,17 @@ +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/main.cpp b/src/standalone/main.cpp similarity index 96% rename from src/main.cpp rename to src/standalone/main.cpp index 88c42a6..8c27a81 100644 --- a/src/main.cpp +++ b/src/standalone/main.cpp @@ -48,6 +48,10 @@ 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/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt new file mode 100644 index 0000000..4e3d6bf --- /dev/null +++ b/test/unit/CMakeLists.txt @@ -0,0 +1,31 @@ +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 new file mode 100644 index 0000000..cae8b5c --- /dev/null +++ b/test/unit/grid_raytrace.cpp @@ -0,0 +1,108 @@ +/* + 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 new file mode 100644 index 0000000..a35d71c --- /dev/null +++ b/test/unit/main.cpp @@ -0,0 +1,21 @@ +/* + 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"