前言

在看MongoDB源码的时候,经常会看到这个玩意儿:invariant。

invariant的字面意思是:不变式。

在emacs上跳转到函数定义要安装一个插件,ggtags,费了老大劲儿。这都可以重开一篇写一下了。

invariant的定义如下:

定义真的是恶心啊。。。

BOOST_PP_OVERLOAD

在看invariant的定义之前,先要了解一下:BOOST_PP_OVERLOAD

The BOOST_PP_OVERLOAD variadic macro expands to the name of a non-variadic macro having a given number of parameters.

Usage

BOOST_PP_OVERLOAD(prefix,...) (v)

Arguments

prefix

The prefix of the non-variadic macro name.
...

Variadic data. The number of variadic data elements, as determined by BOOST_PP_VARIADIC_SIZE, is appended to the prefix to form the output non-variadic macro name.

Remarks

This macro creates a macro name which depends on the number of elements of variadic data. It should be used in the form of
BOOST_PP_OVERLOAD(MACRO_NAME_,__VA_ARGS__)(__VA_ARGS__) in order to call a non-variadic macro taking a given number of variadic data elements as non-variadic arguments. In this way one can invoke a variadic macro with a variable number of parameters which calls one of a series of non-variadic macros doing very similar things.

Requirements

Header: <boost/preprocessor/facilities/overload.hpp>

Sample Code

#include <boost/preprocessor/facilities/overload.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>

#define MACRO_1(number) MACRO_2(number,10)
#define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2)

#define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__)

// or for Visual C++

#define MACRO_ADD_NUMBERS(...) \
BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY())

MACRO_ADD_NUMBERS() // output is 15
MACRO_ADD_NUMBERS(,) // output is 9

BOOST_PP_OVERLOAD试一个可变参数的宏,用来扩展固定参数个数的非可变参数宏。

使用方法

BOOST_PP_OVERLOAD(prefix,...) (v)

prefix:非可变参数宏名称的前缀

...:可变的数据。可变数据元素的个数用BOOST_PP_VARIDIC_SIZE决定,通过prefix和BOOST_PP_VARIDIC_SIZE拼接出非可变参数宏的名称。

说明

这个宏可以根据可变数据的个数来生成一个宏的名称。为了对可变长度的参数调用一个非可变参数的宏,应该使用BOOST_PP_OVERLOAD(MACRO_NAME_,__VA_ARGS__)(__VA_ARGS__)这种形式。

举例

仿照Sample Code,我自己来写一个demo。

#include <iostream>
#include <boost/preprocessor/facilities/overload.hpp>
int add(int number1, int number2);

#define MACRO_1(number) MACRO_2(number, 10)
// mmp, 它会先检查add的原型, 然后再去做替换, 看来这里还是
#define MACRO_2(number1, number2) add(number1, number2)
// 多参数的宏展开实现重载
#define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_, __VA_ARGS__)(__VA_ARGS__)

int main() {
    std::cout << ) << std::endl;
    std::cout << , ) << std::endl;
    ;
}

int add(int number1, int number2) {
    return number1 + number2;
}

对此,我只想说,你们真牛逼,用宏都可以实现重载。

这个是我第一次用到boost库,以后应该会有机会经常用吧,装这个狗玩意儿花了不少时间~

mongo中的invariant

接下来继续看mongo里面的invariant。

#pragma once

#include <boost/preprocessor/facilities/overload.hpp>
#include <string>

#include "mongo/platform/compiler.h"
#include "mongo/util/debug_util.h"

namespace mongo {

/**
 * This include exists so that mongo/base/status_with.h can use the invariant macro without causing
 * a circular include chain. It should never be included directly in any other file other than that
 * one (and assert_util.h).
 */

// 我擦, 这个defined还可以这么用
#if !defined(MONGO_INCLUDE_INVARIANT_H_WHITELISTED)
#error "Include assert_util.h instead of invariant.h."
#endif

// 如果invariant failed会怎么办
MONGO_COMPILER_NORETURN void invariantFailed(const char* expr,
                                             const char* file,
                                             unsigned line) noexcept;

// This overload is our legacy invariant, which just takes a condition to test.
//
// ex)   invariant(!condition);
//
//       Invariant failure !condition some/file.cpp 528
//
// 这个重载是为了测试我们的条件, 比如invariant(!condition), 如果condition不成立的话
// 就会打印这个文件名和对应的行数, 相当于日志功能?
// MONGO_invariant_是宏前缀, 1表示只有一个参数
// 他妈的, #Expression是个鸡毛意思哦
#define MONGO_invariant_1(Expression) \
    ::mongo::invariantWithLocation((Expression), #Expression, __FILE__, __LINE__)

// 模板来了, 模板只能在头文件中使用哦, 内联函数的模板
template <typename T>
inline void invariantWithLocation(const T& testOK,
                                  const char* expr,
                                  const char* file,
                                  unsigned line) {
    if (MONGO_unlikely(!testOK)) {
        // 如果测试不合格就执行下面的函数了
        ::mongo::invariantFailed(expr, file, line);
    }
}

// 同样也是failed的情况
MONGO_COMPILER_NORETURN void invariantFailedWithMsg(const char* expr,
                                                    const std::string& msg,
                                                    const char* file,
                                                    unsigned line) noexcept;

// This invariant overload accepts a condition and a message, to be logged if the condition is
// false.
//
// ex)   invariant(!condition, "hello!");
//
//       Invariant failure !condition "hello!" some/file.cpp 528
//
// 附加了一个信息
#define MONGO_invariant_2(Expression, contextExpr)                                           \
    ::mongo::invariantWithContextAndLocation((Expression),                                   \
                                             #Expression,                                    \
                                             [&]() -> std::string { return (contextExpr); }, \
                                             __FILE__,                                       \
                                             __LINE__)

// 又是一个模板
template <typename T, typename ContextExpr>
inline void invariantWithContextAndLocation(
    const T& testOK, const char* expr, ContextExpr&& contextExpr, const char* file, unsigned line) {
    if (MONGO_unlikely(!testOK)) {
        ::mongo::invariantFailedWithMsg(expr, contextExpr(), file, line);
    }
}

// This helper macro is necessary to make the __VAR_ARGS__ expansion work properly on MSVC.
// 这里还要注意在Microsoft Visual C++里面的坑, 所以专门用了这么个宏
#define MONGO_expand(x) x

// 实现宏重载
#define invariant(...) \
    MONGO_expand(MONGO_expand(BOOST_PP_OVERLOAD(MONGO_invariant_, __VA_ARGS__))(__VA_ARGS__))

// Behaves like invariant in debug builds and is compiled out in release. Use for checks, which can
// potentially be slow or on a critical path.
// 又来了一个assert
#define MONGO_dassert(...) \
    if (kDebugBuild)       \
    invariant(__VA_ARGS__)

#define dassert MONGO_dassert

}  // namespace mongo

反正我是不怕invariant了,我知道这个要干嘛了,哈哈,好多地方都用到了这个玩意儿。其实就是判断一个表达式是否成立,然后打印一下语句,包括文件名和行号这些。

但其实还有几个东西又不懂了,比如#Expression,ContextExpr&&,我们继续哦。

C++中的#和##

C++中的&和&&

mongo源码学习(四)invariant的更多相关文章

  1. mongo源码学习(四)服务入口点ServiceEntryPoint

    在上一篇博客mongo源码学习(三)请求接收传输层中,稍微分析了一下TransportLayer的作用,这篇来看下ServiceEntryPoint是怎么做的. 首先ServiceEntryPoint ...

  2. mongo源码学习(三)请求接收传输层

    在上一篇博客中(mongo源码学习(二)db.cpp之mongoDbMain方法分析),我们把db.cpp中的mongoDbMain的执行过程分析了一下,最后会调用initAndListen(serv ...

  3. mongo源码学习(一)

    在git上把mongo的源码给拉下来了,然后目录大概是这样的: 这个mongo是用C++写的,编译并没有用Makefile而是用的scons工具,这个好像是python写的. mongo后台进程的入口 ...

  4. [spring源码学习]四、IOC源码——普通bean初始化

    一.代码例子 此节开始涉及到一个bean具体生成和保存的过程,仅仅涉及到最简单的bean,代码依旧是最简单的 public static void main(String[] args) { Defa ...

  5. dubbo源码学习(四):暴露服务的过程

    dubbo采用的nio异步的通信,通信协议默认为 netty,当然也可以选择 mina,grizzy.在服务端(provider)在启动时主要是开启netty监听,在zookeeper上注册服务节点, ...

  6. mongo源码学习(二)db.cpp之mongoDbMain方法分析

    mongo后台进程的入口:mongo/src/mongo/db/dbmain.cpp,wmain(for windows)和main函数,main函数也很简单,就是委托给db.cpp中的mongoDb ...

  7. mybatis源码学习(四)--springboot整合mybatis原理

    我们接下来说:springboot是如何和mybatis进行整合的 1.首先,springboot中使用mybatis需要用到mybatis-spring-boot-start,可以理解为mybati ...

  8. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  9. Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

    经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...

随机推荐

  1. 1142 - show view command denied to user

    原因是没有给test用户授予"show_view_priv"权限 mysql> SELECT * FROM mysql.user WHERE User = 'test' an ...

  2. Linux 的僵尸(zombie)进程

    可能很少有人意识到,在一个进程调用了exit之后,该进程 并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构.在Linux进程的5种状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎 ...

  3. C语言下的错误处理的问题

    下面是三种C语言的错误处理,你喜欢哪一种?还是都不喜欢? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /* 问题: 不充分,而且很容易出错,前 ...

  4. 使用 Apache Commons CSV 读写 CSV 文件

    有时候,我们需要读写 CSV 文件,在这里给大家分享Apache Commons CSV,读写 CSV 文件非常方便. 具体官方文档请访问Apache Commons CSV. 官方文档已经写得很详细 ...

  5. 基于axis1.4的webservice实例

    1.准备工作: 概念:SOAP(简单对象访问协议).WSDL(web服务描述语言).XML(可扩展标记语言).axis(阿帕奇可扩展交互系统) (1)     下载axis1.4,将axis1.4中的 ...

  6. JAVA中使用HTTP 1.1提高基于AXIS 1.4的web service的性能

    HTTP 1.1会在第一次连接的时候进行认证, 而在一定时间内保持连接而不用重新验证. 一般情形下,每个web service请求都会在web service服务端验证, 而验证会消耗很多时间, 因此 ...

  7. 第二篇:呈现内容_第一节:Control呈现

    一.Control的呈现过程 在上个章节““生死有序”的控件生命周期”中,我们提到Render是控件开发的主角,但在控件树的“合成模式(Composite)”部分这位主角却缺席了(戏份太多的缘由).哦 ...

  8. Matlab之视角旋转函数[转]

    Matlab中有两个视角旋转函数:view和rotate,下面详细介绍: view: 一: view(az,el):az是方位角,el是仰角,单位均是度.具体: 以x轴从左到右(即从小到大)平行放置在 ...

  9. C# string和byte[]的转换

    转自 http://www.cnblogs.com/Mainz/archive/2008/04/09/String_Byte_Array_Convert_CSharp.html string类型转成b ...

  10. 负载均衡层次结构:LVS Nginx DNS CDN

    文章地址:http://blog.csdn.net/mindfloating/article/details/51020767 作为后端应用的开发者,我们经常开发.调试.测试完我们的应用并发布到生产环 ...