codinghuang

codinghuang 查看完整档案

上海编辑  |  填写毕业院校  |  填写所在公司/组织 127.0.0.1 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

codinghuang 赞了文章 · 6月21日

PHP 完全面向对象风格的 Array 和 String 编程

PHP 语言中操作字符串和数组一般使用 str_*array_* 的系列函数,这些函数由于历史原因,命名和参数顺序风格不统一,广为开发者诟病,PHP 语言标准库中暂未提供 OO 风格的 ArrayString 类库,开发者使用起来不是很便利,在 Swoole 中我们提供了一 swoole_arrayswoole_string 对字符串和数组操作进行了面向对象封装,可以使用完全面向对象风格进行 ArrayString 编程。

使用方法

  • Swoole 项目:可直接使用
  • Swoole 项目,使用 composer require swoole/library 引入

绝大部分方法提供了链式风格支持,可以一路使用 -> 编写逻辑。底层类库使用了 declare(strict_types=1) 强类型,使用 phpstorm 工具时,可以实现完全自动提示和自动完成。

微信截图_20200621154143.png

创建数组

$array1 = swoole_array(['hello', 'world']);
$array2 = swoole_array(['hello' => 1, 'world' => 2]);
$array3 = swoole_array_list('hello', 'world', 'swoole', 'php');

创建字符串

// Bytes 字符串
$string1 = swoole_string('hello world, php java, swoole');
// 宽字符串
$string2 = swoole_mbstring('我是中国人');
// 返回 5
$string2->length(); 

获取元素

// 获取
$value1 = $array1->get(0);
$value2 = $array2->get('hello');

// 数组的第一个元素
$first = $array->first();
// 数组的最后一个元素
$last = $array->last();

增加/设置

// 设置
$array1->set(0, 'swoole');
$array2->set('world', 9);
// 在末尾追加
$array1->pushBack('java');
// 在头部插入
$array1->pushFront('go');
// 在中间 offset 2 插入
$array1->insert(2, 'rust');

连续追加

$array1->append('rust')->append('c++')->append('swift', 'kotlin');
$array2->set('rust', 99)->set('c++', 88)->set('kotlin', 77);

删除

// 按 key 删除
$array1->delete(0);
$array2->delete('worker');
// 按 value 删除
$array1->remove('hello');

包含

使用contains()方法可以判断数组或字符串中是否包含某个元素。

$array1->contains('java');
$string1->contains('php');

使用startsWith()endsWith()方法判断字符串开头和结尾是否为指定的值。

$str = swoole_string('php and swoole');

$str->startsWith('php'); //true
$str->startsWith('java'); //false
$str->endsWith('swoole'); //true
$str->endsWith('golang'); //false

搜索

// 查找数组中是否有某个值,存在则返回其 key
$key = $array1->search('java');

结合使用

StringArray可以结合使用。

$s = '11, 33, 22, 44,12,32,55,23,19,23';

$data = swoole_string($s)
    ->split(',')
    ->each(fn(&$item) => $item = intval($item))
    /* < 7.4 : function (&$item){ $item = intval($item);} */
    ->sort()
    ->unique()
    ->join('-')
    ->contains('-44-');

var_dump($data);
  • 首先构建了一个字符串对象
  • 使用split按照,分割为数组
  • 遍历并应用$fn函数将元素转换为整数
  • 排序
  • 去重
  • 将数组元素使用-组合成为字符串
  • 判断字符串对象中是否包含-44-

类型推断

swoole_array对象元素操作时,底层会自动判断它的类型,如果为数组或字符串,底层会递归封装。

$array = swoole_array_list(['hello' => 'swoole']);
$array->get(0)->get('hello')->contains('swoole');

性能测试

底层实现其实就是基于str_array_相关函数进行面向对象封装,没有过多性能损耗,仅为一次method调用开销。我们编写了严格的单测覆盖到每个API,保证其可靠性。

性能方面,使用String::contains()执行100万次,与直接运行 php strpos差距不大。

swoole_string: 0.059892892837524s, php_string: 0.033510208129883s

源代码

如果您对此项目感兴趣,可以参与到我们的开发工作中,期待您的 Pull Request

查看原文

赞 29 收藏 6 评论 3

codinghuang 提出了问题 · 6月20日

lcov可以对gtest的死亡测试进程覆盖率统计吗?

我尝试用gtest进行死亡测试,但是发现lcov没有对死亡测试的代码进行覆盖。请问如何才能让lcov对gtest的死亡测试进行覆盖呢?

关注 1 回答 0

codinghuang 回答了问题 · 6月14日

swoole 子进程中调用$this 报错

你这不是类方法吧?

关注 2 回答 1

codinghuang 赞了回答 · 6月4日

解决leetcode中的112. Path Sum题?

给你稍微改了下,可以AC了。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        return __hasPathSum(root, sum, 0);
    }

    bool __hasPathSum(TreeNode* root, int sum, int res) {
        
        if (root == NULL) {
            return false;
        }

        if ((res + root->val == sum) && (root->left == NULL) && (root->right == NULL)) {
            return true;
        }

        return __hasPathSum(root->left, sum, res+root->val) || __hasPathSum(root->right, sum, res+root->val);
    }
};

关注 3 回答 2

codinghuang 提出了问题 · 5月30日

使用cmake,make编译出的库可以找到它依赖的动态链接库,但是make install之后,就找不到了?

我的CMakeLists.txt如下:

project(libfsw)

cmake_minimum_required(VERSION 2.8)

enable_language(ASM)
set(FSW_VERSION 0.7.1)
set(FSW_CLFLAGS ssl crypt crypto)
set(CMAKE_CXX_STANDARD 11)
set(ENABLE_DEBUG OFF)
set(ENABLE_TRACE OFF)

if (DEFINED openssl_dir)
    include_directories(BEFORE ${openssl_dir}/include)
    link_directories(${openssl_dir}/lib)
else()
    message(FATAL_ERROR "you should set openssl_dir, eg:
    cmake . -Dopenssl_dir=/usr/local/openssl")
endif()

include(CheckFunctionExists)
check_function_exists(epoll_create HAVE_EPOLL)

option(ENABLE_DEBUGGER "Enable debug" ${ENABLE_DEBUG})
if (ENABLE_DEBUGGER)
    set(ENABLE_DEBUGGER 1)
    message ("-- Enable debug: yes")
else()
    set(ENABLE_DEBUGGER 0)
    message ("-- Enable debug: no")
endif()

option(ENABLE_TRACE "Enable trace" ${ENABLE_TRACE})
if (ENABLE_TRACE)
    set(ENABLE_TRACE 1)
    message ("-- Enable trace: yes")
else()
    set(ENABLE_TRACE 0)
    message ("-- Enable trace: no")
endif()

configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_SOURCE_DIR}/include/config.h)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")

file(GLOB_RECURSE SRC_LIST FOLLOW_SYMLINKS src/*.c src/*.cc thirdparty/boost/asm/combined.S thirdparty/http/http_parser.c)
file(GLOB_RECURSE HEAD_FILES FOLLOW_SYMLINKS include/*.h thirdparty/http/*.h)

set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

include_directories(BEFORE ./include ./thirdparty/http)

#shared library
link_directories(${LIBRARY_OUTPUT_PATH})
add_library(libfsw SHARED ${SRC_LIST})
set_target_properties(libfsw PROPERTIES OUTPUT_NAME "fsw" VERSION ${FSW_VERSION})
target_link_libraries(libfsw ${FSW_CLFLAGS})

#install
install(CODE "MESSAGE(\"Are you run command using root user?\")")
install(TARGETS libfsw LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
install(FILES ${HEAD_FILES} DESTINATION include/fsw)

编译后,通过ldd可以找到所有依赖的动态链接库:

[root@159391e22367 fsw]# ldd lib/libfsw.so
    linux-vdso.so.1 =>  (0x00007ffd670e4000)
    libssl.so.1.1 => /usr/local/openssl/lib/libssl.so.1.1 (0x00007fa28894a000)
    libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fa288713000)
    libcrypto.so.1.1 => /usr/local/openssl/lib/libcrypto.so.1.1 (0x00007fa288229000)
    libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fa287f22000)
    libm.so.6 => /lib64/libm.so.6 (0x00007fa287c20000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fa287a0a000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fa28763c000)
    libz.so.1 => /lib64/libz.so.1 (0x00007fa287426000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fa287222000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fa287006000)
    libfreebl3.so => /lib64/libfreebl3.so (0x00007fa286e03000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fa288e41000)
[root@159391e22367 fsw]#

但是,执行make install之后,就找不到了:

[root@159391e22367 fsw]# make install
[100%] Built target libfsw
Install the project...
-- Install configuration: "Debug"
Are you run command using root user?
-- Up-to-date: /usr/local/lib/libfsw.so.0.7.1
-- Up-to-date: /usr/local/lib/libfsw.so
-- Up-to-date: /usr/local/include/fsw/help.h
-- Up-to-date: /usr/local/include/fsw/error.h
-- Up-to-date: /usr/local/include/fsw/coroutine_channel.h
-- Up-to-date: /usr/local/include/fsw/coroutine_http_server.h
-- Up-to-date: /usr/local/include/fsw/base64.h
-- Up-to-date: /usr/local/include/fsw/config.h
-- Up-to-date: /usr/local/include/fsw/event.h
-- Up-to-date: /usr/local/include/fsw/websocket_frame.h
-- Up-to-date: /usr/local/include/fsw/context.h
-- Up-to-date: /usr/local/include/fsw/coroutine.h
-- Up-to-date: /usr/local/include/fsw/timer.h
-- Up-to-date: /usr/local/include/fsw/buffer.h
-- Up-to-date: /usr/local/include/fsw/asm_context.h
-- Up-to-date: /usr/local/include/fsw/log.h
-- Up-to-date: /usr/local/include/fsw/coroutine_server.h
-- Up-to-date: /usr/local/include/fsw/process.h
-- Up-to-date: /usr/local/include/fsw/coroutine_socket.h
-- Up-to-date: /usr/local/include/fsw/coroutine_http.h
-- Up-to-date: /usr/local/include/fsw/socket.h
-- Up-to-date: /usr/local/include/fsw/unix_socket.h
-- Up-to-date: /usr/local/include/fsw/fsw.h
-- Up-to-date: /usr/local/include/fsw/http_parser.h

[root@159391e22367 fsw]# ldd /usr/local/lib/libfsw.so
    linux-vdso.so.1 =>  (0x00007ffc2d19b000)
    libssl.so.1.1 => not found
    libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fc1c34da000)
    libcrypto.so.1.1 => not found
    libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fc1c31d3000)
    libm.so.6 => /lib64/libm.so.6 (0x00007fc1c2ed1000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc1c2cbb000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fc1c28ed000)
    libfreebl3.so => /lib64/libfreebl3.so (0x00007fc1c26ea000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fc1c3976000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fc1c24e6000)
[root@159391e22367 fsw]#

关注 2 回答 1

codinghuang 赞了回答 · 4月10日

c++可以用某种std::function表达任意的std::function吗?

std::function无法表达任意可调用对象。

如果你需要从callback调用,那么要让一组可调用对象构成重载。

  1. 为callback类型设计一个抽象类。参数用指针或智能指针传递。
  2. 在C++11下可通过模板元编程实现:这里根据你给出的接口设计,提供一个相对完整的实现:https://wandbox.org/permlink/...

如果不需要从callback调用,那么用类似std::variantboost::variant的容器作为形式参数,然后根据事件类型来赋值。


伪代码中的问题:

以下三点对你的伪代码都有不同程度的假设,没有详尽分析可能性。

  1. 调用server::on时,实际参数如果是lambda expression,就得提供模板参数(因为你这样写无法推导),即serv.on<EventData *>("Receive", [](server *serv, EventData *data) {});。如果你想要一个可以推导的写法,那么需要用到类似callable_trait的萃取,这个标准库是没有的。
  2. 函数event_loop里指明了调用时所有可能的参数表,这些参数表必须提供给callbacks。否则server本身得是一个模板才行。
  3. callbacks得是一个异质关联容器,你写的是变量模板声明。boost的c++11下模板元编程库mp11提供了这种容器。

如果以callbacks的声明为重点,那么你思路的技术难点是异质关联容器的访问和修改。你需要熟练掌握这种容器在C++11下的用法。标准库没有提供这方面的支持,最终也不是写一个server类能够完成的。
如果以调用callbacks[event_name](this);为重点,那么抽象类会是一个很好的解决方案,或者用variant
其余部分都会展开太多可能性。

关注 2 回答 1

codinghuang 提出了问题 · 4月7日

c++可以用某种std::function表达任意的std::function吗?

C++版本是11

我的需求是这样的:

我需要实现一个注册事件回调函数的方法,模型如下:

Server::on(std::string event_name, callback handler)
{
}

其中,callback的参数和event_name有关。例如:

int (*onReceive)(Server *, EventData *);
void (*onStart)(Server *serv);

也就是说,我需要用一种callback来表达出以下两种参数的回调函数:

(Server *, EventData *)
(Server *serv)

请问这个可以通过std::function实现吗?或者说有其他的方法实现?

举一个具体的例子,我知道代码会有问题,但是可以更加清晰的表达我的想法:

#include <iostream>
#include <cstdlib>
#include <functional>
#include <vector>

class server
{

public:

template <class... Args>
std::vector<std::string, std::function<void(Args... args)>> callbacks;

template <class... Args>
void on(std::string event_name, std::function<void(server *serv, Args... args)> fn)
{
    callbacks[event_name] = fn;
}

void event_loop(Event event)
{
    if (event == "start")
    {
        callbacks[event_name](this);
    }
    if (event == "receive")
    {
        callbacks[event_name](this, data);
    }
}
};

int main(int argc, char const *argv[])
{
    server serv;

    serv.on("Start", [](server *serv)
    {
    std::cout << "server start..." << std::endl;
    });

    serv.on("Receive", [](server *serv, EventData *data)
    {
    // 读取客户端发来的数据,处理业务逻辑
    });
    
    serv.start(); // 启动服务器

    return 0;
}

关注 2 回答 1

codinghuang 回答了问题 · 3月9日

PHP协程代码执行顺序

和底层实现有关,因为Swoole底层的sleep是通过堆这个数据结构来进行管理的:
30331583743007_.pic.jpg

看不懂这幅图可以先学习下堆这个数据结构。

关注 3 回答 2

codinghuang 提出了问题 · 2月28日

请教一个宏替换的问题?

使用的是C++11

现在有三个宏:

#define CLIENT_INFO_FMT " from session#%u on %s:%d"
#define CLIENT_INFO_ARGS conn->session_id, port->host, port->port
#define CLIENT_INFO CLIENT_INFO_FMT, CLIENT_INFO_ARGS

其中,connportport都是结构体变量。

然后,有一个函数会去使用CLIENT_INFO这个宏,如下:

swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);

直接使用CLIENT_INFO宏展开会有问题,但是如果分别使用CLIENT_INFO_FMTCLIENT_INFO_ARGS的话,就没有问题,即:

swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO_FMT, CLIENT_INFO_ARGS);

如果我把宏CLIENT_INFO修改为:

#define CLIENT_INFO " from session#%u on %s:%d", conn->session_id, port->host, port->port

然后使用CLIENT_INFO宏,即:

swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);

也会展开失败。所以这里的问题就是,为什么要分开使用CLIENT_INFO_FMTCLIENT_INFO_ARGS才行?

调用关系如下:

swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);

#define swoole_error_log(level, __errno, str, ...) \
    do{ \
        SwooleG.error = __errno; \
        if (level >= SwooleG.log_level){ \
            size_t _sw_error_len = sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s (ERRNO %d): " str,__func__,__errno,##__VA_ARGS__); \
            SwooleG.write_log(level, sw_error, _sw_error_len); \
        } \
    } while(0)
    
size_t sw_snprintf(char *buf, size_t size, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    int retval = vsnprintf(buf, size, format, args);
    va_end(args);

vsnprintf会出现段错误。因为format字符串是正确的,所以我判断是va_list出了问题。

关注 2 回答 1

codinghuang 赞了回答 · 2月19日

vscode在开发C++代码的时候,如何过滤掉头文件搜索路径?

"C_Cpp.default.systemIncludePath": null

如果你想去掉是是系统的includepath,可以添加上面的配置。

如果你想不搜索你自定义的include路径,那么久直接删掉就可以了。

关注 2 回答 1

认证与成就

  • 获得 15 次点赞
  • 获得 45 枚徽章 获得 0 枚金徽章, 获得 3 枚银徽章, 获得 42 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-07-12
个人主页被 732 人浏览