Lexer的设计--中(4)
设计一个小型的内存池以及链表
上一节撸到万事俱备只欠真正的lex
, 但是lex
的作用是将源代码转化为Token
流, 用什么保存Token
? 这就涉及到我们要接触的第一个数据结构—链表, 虽然标准库中很多容器都可以承担链表的任务, 但是我说过出于锻炼原因, 我会尽量不使用stl中的容器, 所以我决定自己撸一个链表出来, 既然之后大多数的容器都要自己撸, 干脆连内存池也一并撸一个出来, 所以这一节的两个目的就是 : 内存池以及基于这个内存池的链表.
我个人接触内存池的时间不长, 准确的说我目前脑袋里面只有两中内存池的思路, 一种是sgi stl内存池,我之前有一篇文章专门对这种内存池做过讲解, 但是这里我会使用另外一种较为简易的内存池模型, 因为我认为sgi stl准确来说可以支持频繁地不同大小的内存分配, 而我这里会使用一种简化的思路, 使之每一个内存池只支持单一大小的内存分配. 这种内存池也是从别人那里学过来的, 简图差不多是这样.
然后源代码差不多是这样...
#ifndef FRED_MEMORYPOOL_H
#define FRED_MEMORYPOOL_H
#include <cstdio>
#include <cstdlib>
#include <vector>
template <typename T, size_t NumberForOneNode = 32>
class MemoryPool{
private:
struct node{
void* space;
node* next;
};
node *head, *tail;
size_t left;
void* cur;
protected:
MemoryPool():left(NumberForOneNode){
tail = head = new node;
head->next = 0;
cur = head->space = static_cast<T*>(malloc(sizeof(T) * NumberForOneNode));
}
//Big three
MemoryPool(const MemoryPool&) = delete;
MemoryPool& operator=(const MemoryPool& rhs) = delete;
~MemoryPool();
void* allocate();
};
template <typename T, size_t NumberForOneNode>
MemoryPool<T, NumberForOneNode>::~MemoryPool() {
while(true) {
if (head == tail) {
free(head->space);
delete head;
return;
}
auto temp = head;
head = head->next;
free(temp->space);
delete temp;
}
}
template <typename T, size_t NumberForOneNode>
void* MemoryPool<T, NumberForOneNode>::allocate() {
if(left--){
auto re = cur;
cur = reinterpret_cast<char*>(cur) +sizeof(T);
return re;
}
left = NumberForOneNode;
auto newNode = new node;
newNode->next = 0;
tail = tail->next = newNode;
cur = newNode->space = static_cast<T*>(malloc(sizeof(T) * NumberForOneNode));
allocate();
}
#endif //FRED_MEMORYPOOL_H
图上的变量和代码里面的变量名字都是统一的, 很好理解...
这个内存池的最后一步, 是在这个内存池的基础上, 再套一层封装.
#ifndef FRED_ALLOCATOR_H
#define FRED_ALLOCATOR_H
#include "MemoryPool.h"
template <typename T, size_t NumberForOneNode = 32>
class Allocator : private MemoryPool<T, NumberForOneNode> {
private:
void* buffer[NumberForOneNode];
size_t left;
public:
Allocator():left(0){};
void* allocator(){
if(left){
return buffer[--left];
}
else{
return MemoryPool<T, NumberForOneNode>::allocate();
}
}
void deallocator(T* ptr){
ptr->~T();
if(left == NumberForOneNode){
//full
return;
}
buffer[left++] = ptr;
}
};
#endif //FRED_ALLOCATOR_H
思想其实很简单, 就是如果有空间被送回, 并不直接交还给系统, 而是用这个叫做buffer
的数组存着, 如果之后再有需要, 优先从数组中取, 其实这里用vector
要比buffer
更好, 但是如果想要重利用的空间规模不大的话, buffer
也够用, 就算这个buffer
也不会内存泄漏, 只是有一些空间被浪费了, 等到维护这个allocator
的类卒了, 空间还是要被释放的.
如果想看这个内存池的原版本实现, 可以看这里
有了内存池, 根据我们的需求我们只需要一个链表.
#ifndef FRED_LINKLIST_H
#define FRED_LINKLIST_H
#include "MemoryPool/Allocator.h"
template <typename T>
class LinkList{
private:
struct node{
T item;
struct node* next;
};
Allocator<node> allocator;
node* head;
node* cur;
size_t size;
public:
LinkList():head(0), cur(0), size(0){}
LinkList(const LinkList&) = delete;
LinkList& operator=(const LinkList&) = delete;
~LinkList(){
for(auto temp = head; temp != cur; temp = temp->next){
allocator.deallocator(temp);
}
allocator.deallocator(cur);
}
void pushBack(const T& item){
if(cur) {
cur = cur->next = reinterpret_cast<node*>(new(allocator.allocator())T(item));
}else {
cur = head = reinterpret_cast<node*>(new(allocator.allocator())T(item));
}
++size;
cur->next = 0;
}
node* getHead() const {
return head;
}
};
#endif //FRED_LINKLIST_H
对于这个链表功能和实现都很简单, 这里唯一要说可能有些人不知道new
可以指定空间进行初始化, 不知道的可以去网上看一下, 这是placement new
而我们一般使用的带有内存分配的叫做plain new
...
大概就是这么多, 这个礼拜在成都玩, 可能更新地比较慢...
Lexer的设计--中(4)的更多相关文章
- 数据库设计中的Soft Delete模式
最近几天有点忙,所以我们今天来一篇短的,简单地介绍一下数据库设计中的一种模式——Soft Delete. 可以说,该模式毁誉参半,甚至有非常多的人认为该模式是一个Anti-Pattern.因此在本篇文 ...
- UI设计中的48dp定律【转】
有朋友建议我偶尔写写技术类的文章,所以我打算开始穿插性的写一些偏技术方面的科普文章,尽量往小白能看懂的方向写,今天我来讲讲UI设计中的48dp定律. 那么先说说什么是dp ?其实对于一个非技术人员要把 ...
- 浅谈UI设计中妙用无穷的深色系背景
英文:medium 译者:优设网 - 陈子木 链接:http://www.uisdc.com/ui-benefits-of-dark-background# --------------------- ...
- web设计中那些因素可能影响网站后期优化
web设计中那些因素可能影响网站后期优化. 1.网站代码的简洁实用性.网站源文件html代码.js代码.css代码等应尽可能的压缩处理.能用jquery-min.js的最好不要用jquery.js:c ...
- UI设计中px、pt、ppi、dpi、dp、sp之间的关系
UI设计中px.pt.ppi.dpi.dp.sp之间的关系 武汉AAA数字艺术教育 2015-07-24 14:19:50 职业教育 pi px 阅读(3398) 评论(0) 声明:本文由入驻搜狐公众 ...
- 在你设计中可能用到的20个杂志 PSD 原型
你是否正在为您的印刷产品找一些现成的原型素材?在这里,我们收集了一组免费的杂志 PSD 素材,必将派上用场.这些原型将给你和你的客户一个先睹为快的产品,在现实生活中看起来如何.所有这些原型提供了可以免 ...
- iOS设计中的“代理”
“代理”--在iOS的开发设计中是一个非常重要的概念,同时又是十分基础的知识.所以,掌握“代理”势在必行! 以下,结合一个具体的例子,详细认识“代理”: 1, 图例解释: ①:定义两个文本输入框UIT ...
- AXURE在原型设计中的应用
转: http://uedc.163.com/2248.html 前言 什么是原型呢? 产品原型简单的说就是产品设计成形之前的一个简单框架,对网站来讲,就是将页面模块.元素进行粗放式的排版和布局,深入 ...
- 网页设计中常用的19个Web安全字体
来自http://www.jb51.net 在Web编码中,CSS默认应用的Web字体是有限的,虽然在新版本的CSS3,我们可以通过新增的@font-face属性来引入特殊的浏览器加载字体.但多数情况 ...
随机推荐
- 【9201】&&【a201】明明的随机数
Time Limit: 10 second Memory Limit: 2 MB 问题描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整 ...
- 【35.43%】【hdu 4347】The Closest M Points
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) Total Submissio ...
- 【Z10】引水入城
[题目链接]:http://noi.qz5z.com/viewtask.asp?id=z10 [题解] 对于第一问:从最上面那m个格子开始进行广搜就可以了: 然后看一下最下面那一行有没有被全部覆盖; ...
- [Angular Unit Testing] Testing Services with dependencies
import { Http, Response, ResponseOptions } from '@angular/http'; import { TestBed } from '@angular/c ...
- Deepin系统更新apt-get源
1.复制原文件备份sudo cp /etc/apt/source.list /etc/apt/source.list.bak2.编辑源列表文件sudo vim /etc/apt/source.list ...
- 一小时内破解16位强password
password能够用来保护你的金融交易.你的社交网络站点,和其它貌似安全的在线站点的主机.人们常常说:"不要把字典里的单词用来做password.它们超级不安全". 但是,要是黑 ...
- Opencv 使用Stitcher类图像拼接生成全景图像
Opencv中自带的Stitcher类可以实现全景图像,效果不错.下边的例子是Opencv Samples中的stitching.cpp的简化,源文件可以在这个路径里找到: \opencv\sourc ...
- 判断navigation中父控制器类型
for (UIViewController *controller in self.navigationController.viewControllers) { if ([controller is ...
- BZOJ 2286 消耗战 - 虚树 + 树型dp
传送门 题目大意: 每次给出k个特殊点,回答将这些特殊点与根节点断开至少需要多少代价. 题目分析: 虚树入门 + 树型dp: 刚刚学习完虚树(好文),就来这道入门题签个到. 虚树就是将树中的一些关键点 ...
- scala map的常用操作
package cn.scala_base /** * map常用操作 */ object Map { def main(args: Array[String]): Unit = { //1.不可变m ...