<commit_before>/*

    Copyright <NAME> and <NAME>, 2011, 2012

    This file is part of Lasercake.

    Lasercake is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Lasercake 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "world.hpp"
#include "worldgen.hpp"

#include "tile_iteration.hpp"

using namespace the_decomposition_of_the_world_into_blocks_impl;

namespace the_decomposition_of_the_world_into_blocks_impl {

  void worldblock::construct(world* w, vector3<tile_coordinate> global_position) {
    assert(!w_);
    w_ = w;
    global_position_ = global_position;
    // TODO pass in a nearby node
    // TODO maybe wait until it's been culled
    parent_ = &w_->worldblock_trie_.insert(global_position_ >> worldblock_dimension_exp, this, 1);
    //This was too slow to do for every worldblock:
    //if(assert_everything) {
    //  w_->worldblock_trie_.debug_check_recursive();
    //}
  }

  struct worldblock::helpers {

  // For initialization purposes.  May only be called on a tile marked interior.
  static void initialize_to_non_interior(
      worldblock* wb,
      tile& t,
      worldblock_dimension_type idx,
      worldblock_dimension_type local_x, worldblock_dimension_type local_y, worldblock_dimension_type local_z
  ) {
    assert_if_ASSERT_EVERYTHING(t.is_interior());
    assert_if_ASSERT_EVERYTHING(idx == local_x*worldblock_x_factor + local_y*worldblock_y_factor + local_z*worldblock_z_factor);
    assert_if_ASSERT_EVERYTHING(&t == &wb->tiles_[idx]);
    t.set_interiorness(false);
    wb->count_of_non_interior_tiles_here_ += 1;
    const worldblock_dimension_type interleaved = interleave_worldblock_local_coords(local_x, local_y, local_z);
    const worldblock_dimension_type interleaved_high = interleaved >> 6;
    const worldblock_dimension_type interleaved_low = interleaved & ((1<<6)-1);
    wb->non_interior_bitmap_small_scale_[interleaved_high] |= uint64_t(1) << interleaved_low;
    wb->non_interior_bitmap_large_scale_ |= uint64_t(1) << interleaved_high;

    /*if(wb->count_of_non_interior_tiles_here_ == 1) {
      wb->w_->worldblock_trie_.insert(wb->global_position_ >> worldblock_dimension_exp, wb, 1);
      if(assert_everything) {
        wb->w_->worldblock_trie_.debug_check_recursive();
      }
    }*/
  }
  };

  bool worldblock::is_deletable()const {
    // TODO: maybe only death row for things whose neighbors are
    // all interior too, because tile physics steps a tile or two away
    // from things often.  And so does the display although that neighbor-sides
    // info could be cached per tile.
    // Hmm I wonder about the neighbor realization level; not-very-realized neighbors
    // won't have any known-noninterior tiles...
    if(count_of_non_interior_tiles_here_) { return false; }
    for(worldblock* neighbor : neighbors_) {
      if(neighbor && neighbor->count_of_non_interior_tiles_here_) {
        return false;
      }
    }
    return true;
  }

  void worldblock::set_tile_non_interior(vector3<tile_coordinate> global_coords, worldblock_dimension_type idx) {
    const worldblock_dimension_type x = get_primitive_int(global_coords.x) & (worldblock_dimension-1);
    const worldblock_dimension_type y = get_primitive_int(global_coords.y) & (worldblock_dimension-1);
    const worldblock_dimension_type z = get_primitive_int(global_coords.z) & (worldblock_dimension-1);
    const worldblock_dimension_type interleaved = interleave_worldblock_local_coords(x, y, z);
    const worldblock_dimension_type interleaved_high = interleaved >> 6;
    const worldblock_dimension_type interleaved_low = interleaved & ((1<<6)-1);
    non_interior_bitmap_small_scale_[interleaved_high] |= uint64_t(1) << interleaved_low;
    non_interior_bitmap_large_scale_ |= uint64_t(1) << interleaved_high;
    tile& t = tiles_[idx];
    if(count_of_non_interior_tiles_here_ == 0) {
      assert(parent_);
      parent_->leaf().everything_here_is_interior_this_ = UNSPECIFIED_TILE_CONTENTS;
    }
    count_of_non_interior_tiles_here_ += t.is_interior();
    t.set_interiorness(false);
  }
  void worldblock::set_tile_interior(vector3<tile_coordinate> global_coords, worldblock_dimension_type idx) {
    const worldblock_dimension_type x = get_primitive_int(global_coords.x) & (worldblock_dimension-1);
    const worldblock_dimension_type y = get_primitive_int(global_coords.y) & (worldblock_dimension-1);
    const worldblock_dimension_type z = get_primitive_int(global_coords.z) & (worldblock_dimension-1);
    const worldblock_dimension_type interleaved = interleave_worldblock_local_coords(x, y, z);
    const worldblock_dimension_type interleaved_high = interleaved >> 6;
    const worldblock_dimension_type interleaved_low = interleaved & ((1<<6)-1);
    non_interior_bitmap_small_scale_[interleaved_high] &= ~(uint64_t(1) << interleaved_low);
    non_interior_bitmap_large_scale_ &= ~(uint64_t(!non_interior_bitmap_small_scale_[interleaved_high]) << interleaved_high);
    tile& t = tiles_[idx];
    const bool was_interior = !t.is_interior();
    count_of_non_interior_tiles_here_ -= was_interior;
    t.set_interiorness(true);
    if(was_interior && count_of_non_interior_tiles_here_ == 0) {
      // Hmm who's responsible for propagating this info upwards, and
      // de-propagating it?
      parent_->leaf().everything_here_is_interior_this_ = t.contents();
      // Wait until between frames to deallocate dull worldblocks
      // (this'll sure make tile_physics code simpler)
      // and perhaps wait a few frames to see if it stays all-interior.
      if(this->is_deletable()) {
        w_->suggest_deleting_worldblock(this);
      }
    }
  }

  template<cardinal_direction Dir> struct neighbor_idx_offset;
  template<> struct neighbor_idx_offset<xminus> { static const worldblock_dimension_type value = -worldblock_x_factor; };
  template<> struct neighbor_idx_offset<yminus> { static const worldblock_dimension_type value = -worldblock_y_factor; };
  template<> struct neighbor_idx_offset<zminus> { static const worldblock_dimension_type value = -worldblock_z_factor; };
  template<> struct neighbor_idx_offset<xplus > { static const worldblock_dimension_type value =  worldblock_x_factor; };
  template<> struct neighbor_idx_offset<yplus > { static const worldblock_dimension_type value =  worldblock_y_factor; };
  template<> struct neighbor_idx_offset<zplus > { static const worldblock_dimension_type value =  worldblock_z_factor; };

  template<cardinal_direction Dir>
  inline void initialize_tile_neighbor_interiorness_within_worldblock(
      worldblock* wb,
      worldblock_dimension_type x, worldblock_dimension_type y, worldblock_dimension_type z,
      size_t idx
  ) {
    switch (Dir) {<commit_msg>temp hack to restore worldblock-trie behavior to prior version of sanity<commit_after>/*

    Copyright <NAME> and <NAME>, 2011, 2012

    This file is part of Lasercake.

    Lasercake is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Lasercake 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "world.hpp"
#include "worldgen.hpp"

#include "tile_iteration.hpp"

using namespace the_decomposition_of_the_world_into_blocks_impl;

namespace the_decomposition_of_the_world_into_blocks_impl {


  //just a temp. hack while developing, in between states
  static const bool only_put_non_interiory_blocks_in_the_trie = true;

  void worldblock::construct(world* w, vector3<tile_coordinate> global_position) {
    assert(!w_);
    w_ = w;
    global_position_ = global_position;
    // TODO pass in a nearby node
    // TODO maybe wait until it's been culled
    if(!only_put_non_interiory_blocks_in_the_trie) {
      parent_ = &w_->worldblock_trie_.insert(global_position_ >> worldblock_dimension_exp);
      parent_->leaf().worldblock_ = this;
    }
    //This was too slow to do for every worldblock:
    //if(assert_everything) {
    //  w_->worldblock_trie_.debug_check_recursive();
    //}
  }

  struct worldblock::helpers {

  // For initialization purposes.  May only be called on a tile marked interior.
  static void initialize_to_non_interior(
      worldblock* wb,
      tile& t,
      worldblock_dimension_type idx,
      worldblock_dimension_type local_x, worldblock_dimension_type local_y, worldblock_dimension_type local_z
  ) {
    assert_if_ASSERT_EVERYTHING(t.is_interior());
    assert_if_ASSERT_EVERYTHING(idx == local_x*worldblock_x_factor + local_y*worldblock_y_factor + local_z*worldblock_z_factor);
    assert_if_ASSERT_EVERYTHING(&t == &wb->tiles_[idx]);
    t.set_interiorness(false);
    wb->count_of_non_interior_tiles_here_ += 1;
    const worldblock_dimension_type interleaved = interleave_worldblock_local_coords(local_x, local_y, local_z);
    const worldblock_dimension_type interleaved_high = interleaved >> 6;
    const worldblock_dimension_type interleaved_low = interleaved & ((1<<6)-1);
    wb->non_interior_bitmap_small_scale_[interleaved_high] |= uint64_t(1) << interleaved_low;
    wb->non_interior_bitmap_large_scale_ |= uint64_t(1) << interleaved_high;

    if(only_put_non_interiory_blocks_in_the_trie && wb->count_of_non_interior_tiles_here_ == 1) {
      wb->w_->worldblock_trie_.insert(wb->global_position_ >> worldblock_dimension_exp, wb, 1);
      if(assert_everything) {
        wb->w_->worldblock_trie_.debug_check_recursive();
      }
    }
  }
  };

  bool worldblock::is_deletable()const {
    // TODO: maybe only death row for things whose neighbors are
    // all interior too, because tile physics steps a tile or two away
    // from things often.  And so does the display although that neighbor-sides
    // info could be cached per tile.
    // Hmm I wonder about the neighbor realization level; not-very-realized neighbors
    // won't have any known-noninterior tiles...
    if(count_of_non_interior_tiles_here_) { return false; }
    for(worldblock* neighbor : neighbors_) {
      if(neighbor && neighbor->count_of_non_interior_tiles_here_) {
        return false;
      }
    }
    return true;
  }

  void worldblock::set_tile_non_interior(vector3<tile_coordinate> global_coords, worldblock_dimension_type idx) {
    const worldblock_dimension_type x = get_primitive_int(global_coords.x) & (worldblock_dimension-1);
    const worldblock_dimension_type y = get_primitive_int(global_coords.y) & (worldblock_dimension-1);
    const worldblock_dimension_type z = get_primitive_int(global_coords.z) & (worldblock_dimension-1);
    const worldblock_dimension_type interleaved = interleave_worldblock_local_coords(x, y, z);
    const worldblock_dimension_type interleaved_high = interleaved >> 6;
    const worldblock_dimension_type interleaved_low = interleaved & ((1<<6)-1);
    non_interior_bitmap_small_scale_[interleaved_high] |= uint64_t(1) << interleaved_low;
    non_interior_bitmap_large_scale_ |= uint64_t(1) << interleaved_high;
    tile& t = tiles_[idx];
    if(count_of_non_interior_tiles_here_ == 0) {
      if(only_put_non_interiory_blocks_in_the_trie) {
        w_->worldblock_trie_.insert(global_position_ >> worldblock_dimension_exp, this, 1);
      }
      else {
      assert(parent_);
      parent_->leaf().everything_here_is_interior_this_ = UNSPECIFIED_TILE_CONTENTS;
      }
    }
    count_of_non_interior_tiles_here_ += t.is_interior();
    t.set_interiorness(false);
  }
  void worldblock::set_tile_interior(vector3<tile_coordinate> global_coords, worldblock_dimension_type idx) {
    const worldblock_dimension_type x = get_primitive_int(global_coords.x) & (worldblock_dimension-1);
    const worldblock_dimension_type y = get_primitive_int(global_coords.y) & (worldblock_dimension-1);
    const worldblock_dimension_type z = get_primitive_int(global_coords.z) & (worldblock_dimension-1);
    const worldblock_dimension_type interleaved = interleave_worldblock_local_coords(x, y, z);
    const worldblock_dimension_type interleaved_high = interleaved >> 6;
    const worldblock_dimension_type interleaved_low = interleaved & ((1<<6)-1);
    non_interior_bitmap_small_scale_[interleaved_high] &= ~(uint64_t(1) << interleaved_low);
    non_interior_bitmap_large_scale_ &= ~(uint64_t(!non_interior_bitmap_small_scale_[interleaved_high]) << interleaved_high);
    tile& t = tiles_[idx];
    const bool was_interior = !t.is_interior();
    count_of_non_interior_tiles_here_ -= was_interior;
    t.set_interiorness(true);
    if(was_interior && count_of_non_interior_tiles_here_ == 0) {
      if(only_put_non_interiory_blocks_in_the_trie) {
        w_->worldblock_trie_.erase(global_position_ >> worldblock_dimension_exp);
      }
      else {
      // Hmm who's responsible for propagating this info upwards, and
      // de-propagating it?
      // Should it be part of the monoid?
      // Somehow it would have to persist even when the nodes are deleted; hmm.
      // Also, when the tree is creating a node, how does it know to make
      // the parent invalid
      parent_->leaf().everything_here_is_interior_this_ = t.contents();
      // Wait until between frames to deallocate dull worldblocks
      // (this'll sure make tile_physics code simpler)
      // and perhaps wait a few frames to see if it stays all-interior.
      if(this->is_deletable()) {
        w_->suggest_deleting_worldblock(this);
      }
      }
    }
  }

  template<cardinal_direction Dir> struct neighbor_idx_offset;
  template<> struct neighbor_idx_offset<xminus> { static const worldblock_dimension_type value = -worldblock_x_factor; };
  template<> struct neighbor_idx_offset<yminus> { static const worldblock_dimension_type value = -worldblock_y_factor; };
  template<> struct neighbor_idx_offset<zminus> { static const worldblock_dimension_type value = -worldblock_z_factor; };
  template<> struct neighbor_idx_offset<xplus > { static const worldblock_dimension_type value =  worldblock_x_factor; };
  template<> struct neighbor_idx_offset<yplus > { static const worldblock_dimension_type value =  worldblock_y_factor; };
  template<> struct neighbor_idx_offset<zplus > { static const worldblock_dimension_type value =  worldblock_z_factor; };

  template<cardinal_direction Dir>
  inline void initialize_tile_neighbor_interiorness_within_worldblock(
      worldblock* wb,
      worldblock_dimension_type x, worldblock_dimension_type y, worldblock_dimension_type z,
      size_t idx
  ) {
    switch (Dir) {
{'fraction_non_alphanumeric': 0.08396250976308253, 'fraction_numerical': 0.006899244988284301, 'mean_word_length': 4.499284180386542, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 104, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4034636', 'n_tokens_mistral': 5045, 'n_tokens_neox': 4791, 'n_words': 1107}