klee源码阅读笔记1--STPBuilder类

初始化过程中四个数据成员中的两个数据成员被初始化:
一、vc被初始化为STP提供的C调用接口函数vc_createValidityChecker();
二、optimizeDivides被初始化为false
重点探讨另外两个数据成员。
一、ExprHashMap constructed
ExprHashMap< std::pair<ExprHandle, unsigned> > constructed;
ExprHashMap为一个模板类, 继承unorderedmap,由于自定义Key的类型,因此需要自定义==和hash。
namespace klee {
namespace util {
struct ExprHash {//定义hash
unsigned operator()(const ref<Expr> e) const {
return e->hash();
}
};
struct ExprCmp {//定义==
bool operator()(const ref<Expr> &a, const ref<Expr> &b) const {
return a==b;
}
};
}// namespace util
template<class T>
class ExprHashMap :
public unordered_map<ref<Expr>,
T,
klee::util::ExprHash,
klee::util::ExprCmp> {
};
typedef unordered_set<ref<Expr>,
klee::util::ExprHash,
klee::util::ExprCmp> ExprHashSet;
} //namespace klee
1.1 unordered_map
template<class Key, //The key type.
class Ty, //The mapped type.
class Hash = std::hash<Key>, //The hash function object type.
class Pred = std::equal_to<Key>, //The equality comparison function object type.
class Alloc = std::allocator<std::pair<const Key, Ty> > > //The allocator class.
class unordered_map;
可以看到模板中Hash、Pred、Alloc在未指定的时候是有默认值的。
可以看出Klee中定义ExprHashMap类继承unordered_map类,使用klee::util::ExprHash作为Hash,使用klee::util::ExprCmp作为Pred。键Key的类型是ref<Expr>,T的类型作为模板参数,在实例化的时候具体指定。
博文地址:http://blog.csdn.net/lpstudy/article/details/54345050,c++ unordered_map/set自定义对象的hash,给出了示例代码: (klee传入unordered_map模板的第三个和第四个参数均是funciton object type,在struct结构体中定义==和hash值)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <iomanip> #include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio> using namespace std; //改变这个启用不同的hash方案
#define RECORD_NAMESPACE struct Record
{
string name;
int val;
}; #ifdef RECORD_FUNCTION_OBJECT
struct RecordHash
{
size_t operator()(const Record& rhs) const{
return hash<string>()(rhs.name) ^ hash<int>()(rhs.val);
}
};
struct RecordCmp
{
bool operator()(const Record& lhs, const Record& rhs) const{
return lhs.name == rhs.name && lhs.val == rhs.val;
}
};
unordered_set<Record, RecordHash, RecordCmp> records = {
{ "b", }, { "a", }, { "cc", }, { "d", }, { "d", }
};
#endif//RECORD_FUNCTION_OBJECT #ifdef RECORD_C_FUNCTION
size_t RecordHash(const Record& rhs){
return hash<string>()(rhs.name) ^ hash<int>()(rhs.val);
}
/*
小杰注释:return 后面定义了一个std::hash<std::string>临时变量(第一对圆括号),然后调用该临时变量函数operator()(第二对圆括号,这里是运算符重载),并传rhs.name作为参数。
*/
bool RecordCmp(const Record& lhs, const Record& rhs){
return lhs.name == rhs.name && lhs.val == rhs.val;
}
//直接使用成员初始化列表,vs2013不能编译通过
unordered_set<Record, decltype(&RecordHash), decltype(&RecordCmp)> records = {
,
RecordHash, RecordCmp
};
struct RunBeforeMain
{
RunBeforeMain(){
records.insert({ "a", });
}
};
static RunBeforeMain dummyObject;
#endif //RECORD_C_FUNCTION #ifdef RECORD_LAMBDA
//直接使用auto RecordHash不能编译通过,vs2013
auto &RecordHash = [](const Record& rhs){
return hash<string>()(rhs.name) ^ hash<int>()(rhs.val);
};
auto &RecordCmp = [](const Record& lhs, const Record& rhs){
return lhs.name == rhs.name && lhs.val == rhs.val;
};
unordered_set<Record, decltype(RecordHash), decltype(RecordCmp)> records = {
,
RecordHash, RecordCmp
};
struct RunBeforeMain
{
RunBeforeMain(){
records.insert({ "a", });
}
};
static RunBeforeMain dummyObject;
#endif//RECORD_LAMBDA #ifdef RECORD_NAMESPACE
namespace std{
template<>
struct hash<Record>
{
size_t operator()(const Record& rhs) const{
return hash<string>()(rhs.name) ^ hash<int>()(rhs.val);
}
}; template<>
struct equal_to < Record > {
bool operator()(const Record& lhs, const Record& rhs) const{
return lhs.name == rhs.name && lhs.val == rhs.val;
}
};
}
unordered_set<Record> records = {
{ "b", }, { "a", }, { "cc", }, { "d", }, { "d", }
};
#endif //RECORD_NAMESPACE int main()
{
auto showRecords = [](){
for (auto i : records)
{
cout << "{" << i.name << "," << i.val << "}" << endl;
}
};
showRecords();
return ;
}
说明:对于上述代码中的四种方式,klee使用的是第一种方式。其余三种方式,如何理解?究竟什么含义,这里暂时不深究,我也没有搞明白。引用博文作者的话如下:
|
平时很少用到unordered_set的自定义对象,常用的都是 unordered_map/set是采用hash散列进行存储的,因此存储的对象必须提供两个方法,1,hash告知此容器如何生成hash的值,2,equal_to 告知容器当出现hash冲突的时候,如何区分hash值相同的不同对象 假定要存储的对象的类名为Object,则具体有4种方案: |
1.2 hash和==的定义
struct ExprHash {//定义hash
unsigned operator()(const ref<Expr> e) const {
return e->hash();
}
};
struct ExprCmp {//定义==
bool operator()(const ref<Expr> &a, const ref<Expr> &b) const {
return a==b;
}
};
ref类的主要成员是:
template<class T>
class ref {
T *ptr;
其实ref<Expr>就是定义了一个指针指向Expr类型的实例化对象。
- 首先,Hash值获取:
e->hash调用的就是Expr的hash函数,具体是:
virtual unsigned hash() const { return hashValue; }hashValue是Expr的数据成员,通过computeHash等函数计算得出。
- 其次,==
ref模板类中有如下系列定义:
bool operator==(const ref &rhs) const { return compare(rhs)==; }
int compare(const ref &rhs) const {
assert(!isNull() && !rhs.isNull() && "Invalid call to compare()");
return get()->compare(*rhs.get());
}//为什么是*rhs.get?因为rhs.get()返回的是一个指向T类型对象的指针,(模板参数实例化为Expr),也就是指向Expr类型对象的指针。由于,Expr的compare的参数(见下文),使用的是const Expr &b,因此必须使用解引用符号*,
//将指针指向的具体的Expr类型的对象作为参数传入。然后b就是对改参数的引用。这类似于函数参数类型是int &b,然后你现在有的是int *a,你传入的实际参数肯定是*a。
bool isNull() const { return ptr == 0; }
T *get () const {
return ptr;
}
实际上ref <Expr>类的函数compare,调用的还是T类型对象ptr的compare函数,也就是Expr的compare函数,具体内容在Expr.cpp中:
int Expr::compare(const Expr &b) const {
static ExprEquivSet equivs;
int r = compare(b, equivs);
equivs.clear();
return r;
}
其中,ExprEquivSet的定义是:
typedef llvm::DenseSet<std::pair<const Expr *, const Expr *> > ExprEquivSet;
其次,compare(b, equivs)调用的函数compare的定义是:
int Expr::compare(const Expr &b, ExprEquivSet &equivs) const {
if (this == &b) return ;//this返回的是当前对象的地址(指向当前对象的指针).如果a和b都引用的是同一个对象的地址,那么肯定是相等的;对象地址不同,我们才开始进行比较。
const Expr *ap, *bp;
if (this < &b) {
ap = this; bp = &b;
} else {
ap = &b; bp = this;
}
if (equivs.count(std::make_pair(ap, bp)))
return ;
Kind ak = getKind(), bk = b.getKind();
if (ak!=bk)
return (ak < bk) ? - : ;
if (hashValue != b.hashValue)
return (hashValue < b.hashValue) ? - : ;
if (int res = compareContents(b))
return res;
unsigned aN = getNumKids();
for (unsigned i=; i<aN; i++)
if (int res = getKid(i)->compare(*b.getKid(i), equivs))
return res;
equivs.insert(std::make_pair(ap, bp));
return ;
}
后续的比较过程,由于对Expr类还没有进行深入了解(这是klee表达式Expression机制的核心),所以暂时不讨论。
该随笔会持续更新。
klee源码阅读笔记1--STPBuilder类的更多相关文章
- JDK1.8源码阅读笔记(1)Object类
JDK1.8源码阅读笔记(1)Object类 Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊.Object 类是所有类的基类,当⼀ ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- 源码阅读笔记 - 1 MSVC2015中的std::sort
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
- Three.js源码阅读笔记-5
Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...
- AQS源码阅读笔记(一)
AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...
- libevent源码阅读笔记(一):libevent对epoll的封装
title: libevent源码阅读笔记(一):libevent对epoll的封装 最近开始阅读网络库libevent的源码,阅读源码之前,大致看了张亮写的几篇博文(libevent源码深度剖析 h ...
- HashMap源码阅读笔记
HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述 HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...
随机推荐
- C#只启动一个进程的代码
把写内容过程中经常用到的内容做个收藏,如下的内容是关于C#只启动一个进程的内容.public partial class App : Application { protected override ...
- Android微信支付流程及返回码-1之坑
http://www.51testing.com/html/36/n-3724336.html 之前做微信支付的时候,直接是以库形式引入项目的,虽然一直觉得微信支付的开发文档不太理想,但是印象中也没有 ...
- sql 性能优化相关--总结别人的总结,未做验证,先归纳
sql语句性能达不到你的要求,执行效率让你忍无可忍,一般会时下面几种情况. 网速不给力,不稳定. 服务器内存不够,或者SQL 被分配的内存不够. sql语句设计不合理 没有相应的索引,索引不合理 没有 ...
- SpringCloud---消息驱动的微服务---Spring Cloud Stream
1.概述 1.1 Spring Cloud Stream:用来 为微服务应用 构建 消息驱动能力的框架: 可基于SpringBoot来创建独立.可用于生产的Spring应用程序: 使用Sp ...
- (转)bash条件判断之if语句
http://blog.51cto.com/64314491/1629175---------bash条件判断之if语句(一) http://blog.51cto.com/64314491/16292 ...
- 【lua】LWT HttpdModule
要使用httpd模块,需要在脚本开头添加: require "httpd" httpd.pairs(apr_table) 用以遍历apr_table for key, value ...
- 单元测试工具 - karma
在离开上一家公司之前,team leader 在我离开前留给了我最后几个关键字:karma,断言库,JASMINE,QUNIT,MOCHA. 可一直拖拖沓沓的,没有去了解.直到今天,才终于抽出心情和时 ...
- Xshell关闭导致jar服务终止,使Jar在CentOS后台运行
环境:Xsehll6,CentOS7 在项目文件夹新建一个runjar.sh 在sh中写入(举例说明) nohup java -Dfile.encoding=UTF- -jar fin-mgmt-.j ...
- 架构实战项目心得(六)(补):mongodb.conf参数详解
--dbpath 数据库路径(数据文件)--logpath 日志文件路径--master 指定为主机器--slave 指定为从机器--source 指定主机器的IP地址--pologSize 指定日志 ...
- window.open以post方式提交(转)
function openWindowWithPost(url,name,keys,values) { var newWindow = window.open(url, name); if (!new ...