├── LICENSE ├── README.md └── astar ├── astar.cpp ├── astar.h ├── blockallocator.cpp └── blockallocator.h /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 zhangpanyi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A-Star Algorithm 2 | 这是使用C++实现的高效的A-Star算法。只对算法的程序实现做了尽力而为的优化,并没有对算法自身进行改良。优化措施主要在于:快速判断路径节点是否在开启/关闭列表中、快速查找最小f值的节点以及优化路径节点频繁分配内存的问题。 3 | 4 | # 运行环境 5 | 支持c++11的编译器 6 | 7 | # 使用示例 8 | ```c++ 9 | char maps[10][10] = 10 | { 11 | { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, 12 | { 0, 0, 0, 1, 0, 1, 0, 1, 0, 1 }, 13 | { 1, 1, 1, 1, 0, 1, 0, 1, 0, 1 }, 14 | { 0, 0, 0, 1, 0, 0, 0, 1, 0, 1 }, 15 | { 0, 1, 0, 1, 1, 1, 1, 1, 0, 1 }, 16 | { 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, 17 | { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 18 | { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0 }, 19 | { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0 }, 20 | { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0 }, 21 | }; 22 | 23 | // 搜索参数 24 | AStar::Params param; 25 | param.width = 10; 26 | param.height = 10; 27 | param.corner = false; 28 | param.start = AStar::Vec2(0, 0); 29 | param.end = AStar::Vec2(9, 9); 30 | param.can_pass = [&](const AStar::Vec2 &pos)->bool 31 | { 32 | return maps[pos.y][pos.x] == 0; 33 | }; 34 | 35 | // 执行搜索 36 | BlockAllocator allocator; 37 | AStar algorithm(&allocator); 38 | auto path = algorithm.find(param); 39 | ``` 40 | -------------------------------------------------------------------------------- /astar/astar.cpp: -------------------------------------------------------------------------------- 1 | #include "astar.h" 2 | #include 3 | #include 4 | #include 5 | #include "blockallocator.h" 6 | 7 | static const int kStepValue = 10; 8 | static const int kObliqueValue = 14; 9 | 10 | AStar::AStar(BlockAllocator *allocator) 11 | : width_(0) 12 | , height_(0) 13 | , allocator_(allocator) 14 | , step_val_(kStepValue) 15 | , oblique_val_(kObliqueValue) 16 | { 17 | assert(allocator_ != nullptr); 18 | } 19 | 20 | AStar::~AStar() 21 | { 22 | clear(); 23 | } 24 | 25 | // 获取直行估值 26 | int AStar::get_step_value() const 27 | { 28 | return step_val_; 29 | } 30 | 31 | // 获取拐角估值 32 | int AStar::get_oblique_value() const 33 | { 34 | return oblique_val_; 35 | } 36 | 37 | // 设置直行估值 38 | void AStar::set_step_value(int value) 39 | { 40 | step_val_ = value; 41 | } 42 | 43 | // 获取拐角估值 44 | void AStar::set_oblique_value(int value) 45 | { 46 | oblique_val_ = value; 47 | } 48 | 49 | // 清理参数 50 | void AStar::clear() 51 | { 52 | size_t index = 0; 53 | const size_t max_size = width_ * height_; 54 | while (index < max_size) 55 | { 56 | allocator_->free(mapping_[index++], sizeof(Node)); 57 | } 58 | open_list_.clear(); 59 | can_pass_ = nullptr; 60 | width_ = height_ = 0; 61 | } 62 | 63 | // 初始化操作 64 | void AStar::init(const Params ¶m) 65 | { 66 | width_ = param.width; 67 | height_ = param.height; 68 | can_pass_ = param.can_pass; 69 | if (!mapping_.empty()) 70 | { 71 | memset(&mapping_[0], 0, sizeof(Node*) * mapping_.size()); 72 | } 73 | mapping_.resize(width_ * height_, nullptr); 74 | } 75 | 76 | // 参数是否有效 77 | bool AStar::is_vlid_params(const AStar::Params ¶m) 78 | { 79 | return (param.can_pass != nullptr 80 | && (param.width > 0 && param.height > 0) 81 | && (param.end.x >= 0 && param.end.x < param.width) 82 | && (param.end.y >= 0 && param.end.y < param.height) 83 | && (param.start.x >= 0 && param.start.x < param.width) 84 | && (param.start.y >= 0 && param.start.y < param.height) 85 | ); 86 | } 87 | 88 | // 获取节点索引 89 | bool AStar::get_node_index(Node *node, size_t *index) 90 | { 91 | *index = 0; 92 | const size_t size = open_list_.size(); 93 | while (*index < size) 94 | { 95 | if (open_list_[*index]->pos == node->pos) 96 | { 97 | return true; 98 | } 99 | ++(*index); 100 | } 101 | return false; 102 | } 103 | 104 | // 二叉堆上滤 105 | void AStar::percolate_up(size_t hole) 106 | { 107 | size_t parent = 0; 108 | while (hole > 0) 109 | { 110 | parent = (hole - 1) / 2; 111 | if (open_list_[hole]->f() < open_list_[parent]->f()) 112 | { 113 | std::swap(open_list_[hole], open_list_[parent]); 114 | hole = parent; 115 | } 116 | else 117 | { 118 | return; 119 | } 120 | } 121 | } 122 | 123 | // 计算G值 124 | inline uint16_t AStar::calcul_g_value(Node *parent, const Vec2 ¤t) 125 | { 126 | uint16_t g_value = current.distance(parent->pos) == 2 ? oblique_val_ : step_val_; 127 | return g_value += parent->g; 128 | } 129 | 130 | // 计算F值 131 | inline uint16_t AStar::calcul_h_value(const Vec2 ¤t, const Vec2 &end) 132 | { 133 | unsigned int h_value = end.distance(current); 134 | return h_value * step_val_; 135 | } 136 | 137 | // 节点是否存在于开启列表 138 | inline bool AStar::in_open_list(const Vec2 &pos, Node *&out_node) 139 | { 140 | out_node = mapping_[pos.y * width_ + pos.x]; 141 | return out_node ? out_node->state == IN_OPENLIST : false; 142 | } 143 | 144 | // 节点是否存在于关闭列表 145 | inline bool AStar::in_closed_list(const Vec2 &pos) 146 | { 147 | Node *node_ptr = mapping_[pos.y * width_ + pos.x]; 148 | return node_ptr ? node_ptr->state == IN_CLOSEDLIST : false; 149 | } 150 | 151 | // 是否可到达 152 | bool AStar::can_pass(const Vec2 &pos) 153 | { 154 | return (pos.x >= 0 && pos.x < width_ && pos.y >= 0 && pos.y < height_) ? can_pass_(pos) : false; 155 | } 156 | 157 | // 当前点是否可到达目标点 158 | bool AStar::can_pass(const Vec2 ¤t, const Vec2 &destination, bool allow_corner) 159 | { 160 | if (destination.x >= 0 && destination.x < width_ && destination.y >= 0 && destination.y < height_) 161 | { 162 | if (in_closed_list(destination)) 163 | { 164 | return false; 165 | } 166 | 167 | if (destination.distance(current) == 1) 168 | { 169 | return can_pass_(destination); 170 | } 171 | else if (allow_corner) 172 | { 173 | return can_pass_(destination) && (can_pass(Vec2(current.x + destination.x - current.x, current.y)) 174 | && can_pass(Vec2(current.x, current.y + destination.y - current.y))); 175 | } 176 | } 177 | return false; 178 | } 179 | 180 | // 查找附近可通过的节点 181 | void AStar::find_can_pass_nodes(const Vec2 ¤t, bool corner, std::vector *out_lists) 182 | { 183 | Vec2 destination; 184 | int row_index = current.y - 1; 185 | const int max_row = current.y + 1; 186 | const int max_col = current.x + 1; 187 | 188 | if (row_index < 0) 189 | { 190 | row_index = 0; 191 | } 192 | 193 | while (row_index <= max_row) 194 | { 195 | int col_index = current.x - 1; 196 | 197 | if (col_index < 0) 198 | { 199 | col_index = 0; 200 | } 201 | 202 | while (col_index <= max_col) 203 | { 204 | destination.reset(col_index, row_index); 205 | if (can_pass(current, destination, corner)) 206 | { 207 | out_lists->push_back(destination); 208 | } 209 | ++col_index; 210 | } 211 | ++row_index; 212 | } 213 | } 214 | 215 | // 处理找到节点的情况 216 | void AStar::handle_found_node(Node *current, Node *destination) 217 | { 218 | unsigned int g_value = calcul_g_value(current, destination->pos); 219 | if (g_value < destination->g) 220 | { 221 | destination->g = g_value; 222 | destination->parent = current; 223 | 224 | size_t index = 0; 225 | if (get_node_index(destination, &index)) 226 | { 227 | percolate_up(index); 228 | } 229 | else 230 | { 231 | assert(false); 232 | } 233 | } 234 | } 235 | 236 | // 处理未找到节点的情况 237 | void AStar::handle_not_found_node(Node *current, Node *destination, const Vec2 &end) 238 | { 239 | destination->parent = current; 240 | destination->h = calcul_h_value(destination->pos, end); 241 | destination->g = calcul_g_value(current, destination->pos); 242 | 243 | Node *&reference_node = mapping_[destination->pos.y * width_ + destination->pos.x]; 244 | reference_node = destination; 245 | reference_node->state = IN_OPENLIST; 246 | 247 | open_list_.push_back(destination); 248 | std::push_heap(open_list_.begin(), open_list_.end(), [](const Node *a, const Node *b)->bool 249 | { 250 | return a->f() > b->f(); 251 | }); 252 | } 253 | 254 | // 执行寻路操作 255 | std::vector AStar::find(const Params ¶m) 256 | { 257 | std::vector paths; 258 | assert(is_vlid_params(param)); 259 | if (!is_vlid_params(param)) 260 | { 261 | return paths; 262 | } 263 | 264 | // 初始化 265 | init(param); 266 | std::vector nearby_nodes; 267 | nearby_nodes.reserve(param.corner ? 8 : 4); 268 | 269 | // 将起点放入开启列表 270 | Node *start_node = new(allocator_->allocate(sizeof(Node))) Node(param.start); 271 | open_list_.push_back(start_node); 272 | Node *&reference_node = mapping_[start_node->pos.y * width_ + start_node->pos.x]; 273 | reference_node = start_node; 274 | reference_node->state = IN_OPENLIST; 275 | 276 | // 寻路操作 277 | while (!open_list_.empty()) 278 | { 279 | // 找出f值最小节点 280 | Node *current = open_list_.front(); 281 | std::pop_heap(open_list_.begin(), open_list_.end(), [](const Node *a, const Node *b)->bool 282 | { 283 | return a->f() > b->f(); 284 | }); 285 | open_list_.pop_back(); 286 | mapping_[current->pos.y * width_ + current->pos.x]->state = IN_CLOSEDLIST; 287 | 288 | // 是否找到终点 289 | if (current->pos == param.end) 290 | { 291 | while (current->parent) 292 | { 293 | paths.push_back(current->pos); 294 | current = current->parent; 295 | } 296 | std::reverse(paths.begin(), paths.end()); 297 | goto __end__; 298 | } 299 | 300 | // 查找周围可通过节点 301 | nearby_nodes.clear(); 302 | find_can_pass_nodes(current->pos, param.corner, &nearby_nodes); 303 | 304 | // 计算周围节点的估值 305 | size_t index = 0; 306 | const size_t size = nearby_nodes.size(); 307 | while (index < size) 308 | { 309 | Node *next_node = nullptr; 310 | if (in_open_list(nearby_nodes[index], next_node)) 311 | { 312 | handle_found_node(current, next_node); 313 | } 314 | else 315 | { 316 | next_node = new(allocator_->allocate(sizeof(Node))) Node(nearby_nodes[index]); 317 | handle_not_found_node(current, next_node, param.end); 318 | } 319 | ++index; 320 | } 321 | } 322 | 323 | __end__: 324 | clear(); 325 | return paths; 326 | } 327 | -------------------------------------------------------------------------------- /astar/astar.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASTAR_H__ 2 | #define __ASTAR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BlockAllocator; 10 | 11 | class AStar 12 | { 13 | public: 14 | /** 15 | * 二维向量 16 | */ 17 | struct Vec2 18 | { 19 | uint16_t x; 20 | uint16_t y; 21 | 22 | Vec2() : x(0) , y(0) 23 | { 24 | } 25 | 26 | Vec2(uint16_t x1, uint16_t y1) : x(x1), y(y1) 27 | { 28 | } 29 | 30 | void reset(uint16_t x1, uint16_t y1) 31 | { 32 | x = x1; 33 | y = y1; 34 | } 35 | 36 | int distance(const Vec2 &other) const 37 | { 38 | return abs(other.x - x) + abs(other.y - y); 39 | } 40 | 41 | bool operator== (const Vec2 &other) const 42 | { 43 | return x == other.x && y == other.y; 44 | } 45 | }; 46 | 47 | typedef std::function Callback; 48 | 49 | /** 50 | * 搜索参数 51 | */ 52 | struct Params 53 | { 54 | bool corner; // 允许拐角 55 | uint16_t height; // 地图高度 56 | uint16_t width; // 地图宽度 57 | Vec2 start; // 起点坐标 58 | Vec2 end; // 终点坐标 59 | Callback can_pass; // 是否可通过 60 | 61 | Params() : height(0), width(0), corner(false) 62 | { 63 | } 64 | }; 65 | 66 | private: 67 | /** 68 | * 路径节点状态 69 | */ 70 | enum NodeState 71 | { 72 | NOTEXIST, // 不存在 73 | IN_OPENLIST, // 在开启列表 74 | IN_CLOSEDLIST // 在关闭列表 75 | }; 76 | 77 | /** 78 | * 路径节点 79 | */ 80 | struct Node 81 | { 82 | uint16_t g; // 与起点距离 83 | uint16_t h; // 与终点距离 84 | Vec2 pos; // 节点位置 85 | NodeState state; // 节点状态 86 | Node* parent; // 父节点 87 | 88 | /** 89 | * 计算f值 90 | */ 91 | int f() const 92 | { 93 | return g + h; 94 | } 95 | 96 | inline Node(const Vec2 &pos) 97 | : g(0), h(0), pos(pos), parent(nullptr), state(NOTEXIST) 98 | { 99 | } 100 | }; 101 | 102 | public: 103 | AStar(BlockAllocator *allocator); 104 | 105 | ~AStar(); 106 | 107 | public: 108 | /** 109 | * 获取直行估值 110 | */ 111 | int get_step_value() const; 112 | 113 | /** 114 | * 获取拐角估值 115 | */ 116 | int get_oblique_value() const; 117 | 118 | /** 119 | * 设置直行估值 120 | */ 121 | void set_step_value(int value); 122 | 123 | /** 124 | * 获取拐角估值 125 | */ 126 | void set_oblique_value(int value); 127 | 128 | /** 129 | * 执行寻路操作 130 | */ 131 | std::vector find(const Params ¶m); 132 | 133 | private: 134 | /** 135 | * 清理参数 136 | */ 137 | void clear(); 138 | 139 | /** 140 | * 初始化参数 141 | */ 142 | void init(const Params ¶m); 143 | 144 | /** 145 | * 参数是否有效 146 | */ 147 | bool is_vlid_params(const Params ¶m); 148 | 149 | private: 150 | /** 151 | * 二叉堆上滤 152 | */ 153 | void percolate_up(size_t hole); 154 | 155 | /** 156 | * 获取节点索引 157 | */ 158 | bool get_node_index(Node *node, size_t *index); 159 | 160 | /** 161 | * 计算G值 162 | */ 163 | uint16_t calcul_g_value(Node *parent, const Vec2 ¤t); 164 | 165 | /** 166 | * 计算F值 167 | */ 168 | uint16_t calcul_h_value(const Vec2 ¤t, const Vec2 &end); 169 | 170 | /** 171 | * 节点是否存在于开启列表 172 | */ 173 | bool in_open_list(const Vec2 &pos, Node *&out_node); 174 | 175 | /** 176 | * 节点是否存在于关闭列表 177 | */ 178 | bool in_closed_list(const Vec2 &pos); 179 | 180 | /** 181 | * 是否可通过 182 | */ 183 | bool can_pass(const Vec2 &pos); 184 | 185 | /** 186 | * 当前点是否可到达目标点 187 | */ 188 | bool can_pass(const Vec2 ¤t, const Vec2 &destination, bool allow_corner); 189 | 190 | /** 191 | * 查找附近可通过的节点 192 | */ 193 | void find_can_pass_nodes(const Vec2 ¤t, bool allow_corner, std::vector *out_lists); 194 | 195 | /** 196 | * 处理找到节点的情况 197 | */ 198 | void handle_found_node(Node *current, Node *destination); 199 | 200 | /** 201 | * 处理未找到节点的情况 202 | */ 203 | void handle_not_found_node(Node *current, Node *destination, const Vec2 &end); 204 | 205 | private: 206 | int step_val_; 207 | int oblique_val_; 208 | std::vector mapping_; 209 | uint16_t height_; 210 | uint16_t width_; 211 | Callback can_pass_; 212 | std::vector open_list_; 213 | BlockAllocator* allocator_; 214 | }; 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /astar/blockallocator.cpp: -------------------------------------------------------------------------------- 1 | #include "blockallocator.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct Chunk 9 | { 10 | int block_size; 11 | Block *blocks; 12 | }; 13 | 14 | struct Block 15 | { 16 | Block *next; 17 | }; 18 | 19 | int BlockAllocator::block_sizes_[kBlockSizes] = 20 | { 21 | 16, // 0 22 | 32, // 1 23 | 64, // 2 24 | 96, // 3 25 | 128, // 4 26 | 160, // 5 27 | 192, // 6 28 | 224, // 7 29 | 256, // 8 30 | 320, // 9 31 | 384, // 10 32 | 448, // 11 33 | 512, // 12 34 | 640, // 13 35 | }; 36 | 37 | bool BlockAllocator::s_block_size_lookup_initialized_; 38 | 39 | uint8_t BlockAllocator::s_block_size_lookup_[kMaxBlockSize + 1]; 40 | 41 | BlockAllocator::BlockAllocator() 42 | { 43 | assert(kBlockSizes < UCHAR_MAX); 44 | 45 | num_chunk_space_ = kChunkArrayIncrement; 46 | num_chunk_count_ = 0; 47 | chunks_ = (Chunk *)malloc(num_chunk_space_ * sizeof(Chunk)); 48 | 49 | memset(chunks_, 0, num_chunk_space_ * sizeof(Chunk)); 50 | memset(free_lists_, 0, sizeof(free_lists_)); 51 | 52 | if (s_block_size_lookup_initialized_ == false) 53 | { 54 | int j = 0; 55 | for (int i = 1; i <= kMaxBlockSize; ++i) 56 | { 57 | assert(j < kBlockSizes); 58 | if (i <= block_sizes_[j]) 59 | { 60 | s_block_size_lookup_[i] = (uint8_t)j; 61 | } 62 | else 63 | { 64 | ++j; 65 | s_block_size_lookup_[i] = (uint8_t)j; 66 | } 67 | } 68 | s_block_size_lookup_initialized_ = true; 69 | } 70 | } 71 | 72 | BlockAllocator::~BlockAllocator() 73 | { 74 | for (int i = 0; i < num_chunk_count_; ++i) 75 | { 76 | ::free(chunks_[i].blocks); 77 | } 78 | ::free(chunks_); 79 | } 80 | 81 | void* BlockAllocator::allocate(int size) 82 | { 83 | if (size == 0) 84 | { 85 | return nullptr; 86 | } 87 | 88 | assert(0 < size); 89 | 90 | if (size > kMaxBlockSize) 91 | { 92 | return malloc(size); 93 | } 94 | 95 | int index = s_block_size_lookup_[size]; 96 | assert(0 <= index && index < kBlockSizes); 97 | 98 | if (free_lists_[index]) 99 | { 100 | Block *block = free_lists_[index]; 101 | free_lists_[index] = block->next; 102 | return block; 103 | } 104 | else 105 | { 106 | if (num_chunk_count_ == num_chunk_space_) 107 | { 108 | Chunk *oldChunks = chunks_; 109 | num_chunk_space_ += kChunkArrayIncrement; 110 | chunks_ = (Chunk *)malloc(num_chunk_space_ * sizeof(Chunk)); 111 | memcpy(chunks_, oldChunks, num_chunk_count_ * sizeof(Chunk)); 112 | memset(chunks_ + num_chunk_count_, 0, kChunkArrayIncrement * sizeof(Chunk)); 113 | ::free(oldChunks); 114 | } 115 | 116 | Chunk *chunk = chunks_ + num_chunk_count_; 117 | chunk->blocks = (Block *)malloc(kChunkSize); 118 | #if defined(_DEBUG) 119 | memset(chunk->blocks, 0xcd, kChunkSize); 120 | #endif 121 | int block_size = block_sizes_[index]; 122 | chunk->block_size = block_size; 123 | int block_count = kChunkSize / block_size; 124 | assert(block_count * block_size <= kChunkSize); 125 | for (int i = 0; i < block_count - 1; ++i) 126 | { 127 | Block *block = (Block *)((uint8_t *)chunk->blocks + block_size * i); 128 | Block *next = (Block *)((uint8_t *)chunk->blocks + block_size * (i + 1)); 129 | block->next = next; 130 | } 131 | Block *last = (Block *)((uint8_t *)chunk->blocks + block_size * (block_count - 1)); 132 | last->next = nullptr; 133 | 134 | free_lists_[index] = chunk->blocks->next; 135 | ++num_chunk_count_; 136 | 137 | return chunk->blocks; 138 | } 139 | } 140 | 141 | void BlockAllocator::free(void *p, int size) 142 | { 143 | if (size == 0 || p == nullptr) 144 | { 145 | return; 146 | } 147 | 148 | assert(0 < size); 149 | 150 | if (size > kMaxBlockSize) 151 | { 152 | ::free(p); 153 | return; 154 | } 155 | 156 | int index = s_block_size_lookup_[size]; 157 | assert(0 <= index && index < kBlockSizes); 158 | 159 | #ifdef _DEBUG 160 | int block_size = block_sizes_[index]; 161 | bool found = false; 162 | for (int i = 0; i < num_chunk_count_; ++i) 163 | { 164 | Chunk *chunk = chunks_ + i; 165 | if (chunk->block_size != block_size) 166 | { 167 | assert((uint8_t *)p + block_size <= (uint8_t *)chunk->blocks || 168 | (uint8_t *)chunk->blocks + kChunkSize <= (uint8_t *)p); 169 | } 170 | else 171 | { 172 | if ((uint8_t *)chunk->blocks <= (uint8_t *)p && (uint8_t *)p + block_size <= (uint8_t *)chunk->blocks + kChunkSize) 173 | { 174 | found = true; 175 | } 176 | } 177 | } 178 | 179 | assert(found); 180 | 181 | memset(p, 0xfd, block_size); 182 | #endif 183 | 184 | Block *block = (Block *)p; 185 | block->next = free_lists_[index]; 186 | free_lists_[index] = block; 187 | } 188 | 189 | void BlockAllocator::clear() 190 | { 191 | for (int i = 0; i < num_chunk_count_; ++i) 192 | { 193 | ::free(chunks_[i].blocks); 194 | } 195 | 196 | num_chunk_count_ = 0; 197 | memset(chunks_, 0, num_chunk_space_ * sizeof(Chunk)); 198 | memset(free_lists_, 0, sizeof(free_lists_)); 199 | } 200 | -------------------------------------------------------------------------------- /astar/blockallocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * Permission is granted to anyone to use this software for any purpose, 8 | * including commercial applications, and to alter it and redistribute it 9 | * freely, subject to the following restrictions: 10 | * 1. The origin of this software must not be misrepresented; you must not 11 | * claim that you wrote the original software. If you use this software 12 | * in a product, an acknowledgment in the product documentation would be 13 | * appreciated but is not required. 14 | * 2. Altered source versions must be plainly marked as such, and must not be 15 | * misrepresented as being the original software. 16 | * 3. This notice may not be removed or altered from any source distribution. 17 | */ 18 | 19 | #ifndef __BLOCKALLOCATOR_H__ 20 | #define __BLOCKALLOCATOR_H__ 21 | 22 | #include 23 | 24 | /// This is a small object allocator used for allocating small 25 | /// objects that persist for more than one time step. 26 | /// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp 27 | class BlockAllocator 28 | { 29 | static const int kChunkSize = 16 * 1024; 30 | static const int kMaxBlockSize = 640; 31 | static const int kBlockSizes = 14; 32 | static const int kChunkArrayIncrement = 128; 33 | 34 | public: 35 | BlockAllocator(); 36 | ~BlockAllocator(); 37 | 38 | public: 39 | void* allocate(int size); 40 | void free(void *p, int size); 41 | void clear(); 42 | 43 | private: 44 | int num_chunk_count_; 45 | int num_chunk_space_; 46 | struct Chunk* chunks_; 47 | struct Block* free_lists_[kBlockSizes]; 48 | static int block_sizes_[kBlockSizes]; 49 | static uint8_t s_block_size_lookup_[kMaxBlockSize + 1]; 50 | static bool s_block_size_lookup_initialized_; 51 | }; 52 | 53 | #endif 54 | --------------------------------------------------------------------------------