boost::multi_index_container
是Boost库中的一个重要组件,它定义了一个具有多个索引方式的容器,使得用户可以从不同的维度对元素进行索引、排序和存取。以下是对boost::multi_index_container
的详细介绍:
一、基本概念
boost::multi_index_container
是一个模板类,它允许在同一个容器中维护多个索引,每个索引都可以用于不同的排序和访问方式。这些索引可以是唯一的,也可以是非唯一的,类似于数据库中的主键和次键。
二、索引类型
boost::multi_index_container
支持多种索引类型,包括但不限于:
- 有序索引(ordered_index):根据元素的某个属性进行排序。有序索引可以是唯一的(
ordered_unique
),也可以是非唯一的(ordered_non_unique
)。 - 哈希索引(hashed_index):基于哈希表实现,提供快速的元素查找功能。
- 序列索引(sequenced_index):保持元素插入的顺序,类似于
std::vector
或std::deque
。
三、使用示例
以下是一个简单的使用示例,展示了如何定义一个boost::multi_index_container
,并基于学生信息结构体实现按ID、姓名和分数排序:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <string>
using namespace std;
// 定义学生信息结构体
struct student {
int id;
string name;
int score;
string remark;
student(int id, string name, int score, string remark)
: id(id), name(name), score(score), remark(remark) {}
void print() const {
cout << "id:" << id << " name:" << name << " score:" << score << endl;
}
};
// 定义用于排序的空结构体对象,作为索引的标签
struct _id {};
struct _name {};
struct _score {};
// 定义一个multi_index_container(多索引容器)
using student_table = boost::multi_index::multi_index_container<
student,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::tag<_id>,
BOOST_MULTI_INDEX_MEMBER(student, int, id)
>, // ID为唯一索引,类似主键
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<_name>,
BOOST_MULTI_INDEX_MEMBER(student, string, name)
>, // 非唯一索引
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<_score>,
BOOST_MULTI_INDEX_MEMBER(student, int, score)
>
>
>;
int main() {
// 初始化数据
student_table allStu;
allStu.insert(student(1, "lili", 85, "hello"));
allStu.insert(student(2, "liming", 90, "hello"));
allStu.insert(student(3, "xiaoming", 65, "hello"));
allStu.insert(student(4, "ergou", 80, "hello"));
allStu.insert(student(5, "dagou", 60, "hello"));
// 按ID排序并输出
student_table::index<_id>::type& sort_id = allStu.get<0>();
cout << "sort by student id:" << endl;
for (auto iter_id = sort_id.begin(); iter_id != sort_id.end(); iter_id++) {
iter_id->print();
}
// 按姓名排序并输出
student_table::index<_name>::type& sort_name = allStu.get<1>();
cout << "\nsort by student name:" << endl;
for (auto iter_name = sort_name.begin(); iter_name != sort_name.end(); iter_name++) {
iter_name->print();
}
// 按分数排序并输出
student_table::index<_score>::type& sort_score = allStu.get<2>();
cout << "\nsort by student score:" << endl;
for (auto iter_score = sort_score.begin(); iter_score != sort_score.end(); iter_score++) {
iter_score->print();
}
return 0;
}
四、注意事项
- 唯一性约束:当定义唯一索引时(如
ordered_unique
),插入或替换元素时必须确保新值的主键字段值的唯一性,否则insert()
或replace()
操作会失败。 - 数据修改:修改数据之后,必须通过
replace()
方法提交修改,以更新各个索引。不能直接通过迭代器修改元素的值,因为这可能会在不通知容器的情况下引入不一致性。 - 索引标签:为索引增加标签可以方便地通过标签名访问索引,而不需要记住索引的序号。同时,一个索引项可以有多个标签。
综上所述,boost::multi_index_container
是一个功能强大的多索引容器,它提供了灵活且高效的元素索引、排序和访问方式。通过合理使用该容器,可以大大提高程序的性能和可维护性。
1,TimeoutQueue头文件代码
/*
* Copyright 2011-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Simple timeout queue. Call user-specified callbacks when their timeouts
* expire.
*
* This class assumes that "time" is an int64_t and doesn't care about time
* units (seconds, milliseconds, etc). You call runOnce() / runLoop() using
* the same time units that you use to specify callbacks.
*
* @author Tudor Bosman (tudorb@fb.com)
*/
#pragma once
#include <cstdint>
#include <functional>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index_container.hpp>
namespace folly {
class TimeoutQueue {
public:
typedef int64_t Id;
typedef std::function<void(Id, int64_t)> Callback;
TimeoutQueue() : nextId_(1) { }
/**
* Add a one-time timeout event that will fire "delay" time units from "now"
* (that is, the first time that run*() is called with a time value >= now
* + delay).
*/
Id add(int64_t now, int64_t delay, Callback callback);
/**
* Add a repeating timeout event that will fire every "interval" time units
* (it will first fire when run*() is called with a time value >=
* now + interval).
*
* run*() will always invoke each repeating event at most once, even if
* more than one "interval" period has passed.
*/
Id addRepeating(int64_t now, int64_t interval, Callback callback);
/**
* Erase a given timeout event, returns true if the event was actually
* erased and false if it didn't exist in our queue.
*/
bool erase(Id id);
/**
* Process all events that are due at times <= "now" by calling their
* callbacks.
*
* Callbacks are allowed to call back into the queue and add / erase events;
* they might create more events that are already due. In this case,
* runOnce() will only go through the queue once, and return a "next
* expiration" time in the past or present (<= now); runLoop()
* will process the queue again, until there are no events already due.
*
* Note that it is then possible for runLoop to never return if
* callbacks re-add themselves to the queue (or if you have repeating
* callbacks with an interval of 0).
*
* Return the time that the next event will be due (same as
* nextExpiration(), below)
*/
int64_t runOnce(int64_t now) { return runInternal(now, true); }
int64_t runLoop(int64_t now) { return runInternal(now, false); }
/**
* Return the time that the next event will be due.
*/
int64_t nextExpiration() const;
private:
int64_t runInternal(int64_t now, bool runOnce);
// noncopyable
TimeoutQueue(const TimeoutQueue&) = delete;
TimeoutQueue& operator=(const TimeoutQueue&) = delete;
struct Event {
Id id;
int64_t expiration;
int64_t repeatInterval;
Callback callback;
};
typedef boost::multi_index_container<
Event,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<boost::multi_index::member<
Event, Id, &Event::id
>>,
boost::multi_index::ordered_non_unique<boost::multi_index::member<
Event, int64_t, &Event::expiration
>>
>
> Set;
enum {
BY_ID=0,
BY_EXPIRATION=1
};
Set timeouts_;
Id nextId_;
};
} // namespace folly
源文件代码
/*
* Copyright 2011-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/TimeoutQueue.h>
#include <algorithm>
#include <vector>
namespace folly {
TimeoutQueue::Id
TimeoutQueue::add(int64_t now, int64_t delay, Callback callback) {
Id id = nextId_++;
timeouts_.insert({id, now + delay, -1, std::move(callback)});
return id;
}
TimeoutQueue::Id
TimeoutQueue::addRepeating(int64_t now, int64_t interval, Callback callback) {
Id id = nextId_++;
timeouts_.insert({id, now + interval, interval, std::move(callback)});
return id;
}
int64_t TimeoutQueue::nextExpiration() const {
return (
timeouts_.empty() ? std::numeric_limits<int64_t>::max()
: timeouts_.get<BY_EXPIRATION>().begin()->expiration);
}
bool TimeoutQueue::erase(Id id) {
return timeouts_.get<BY_ID>().erase(id);
}
int64_t TimeoutQueue::runInternal(int64_t now, bool onceOnly) {
auto& byExpiration = timeouts_.get<BY_EXPIRATION>();
int64_t nextExp;
do {
const auto end = byExpiration.upper_bound(now);
std::vector<Event> expired;
std::move(byExpiration.begin(), end, std::back_inserter(expired));
byExpiration.erase(byExpiration.begin(), end);
for (const auto& event : expired) {
// Reinsert if repeating, do this before executing callbacks
// so the callbacks have a chance to call erase
if (event.repeatInterval >= 0) {
timeouts_.insert({event.id,
now + event.repeatInterval,
event.repeatInterval,
event.callback});
}
}
// Call callbacks
for (const auto& event : expired) {
event.callback(event.id, now);
}
nextExp = nextExpiration();
} while (!onceOnly && nextExp <= now);
return nextExp;
}
} // namespace folly
这个消息队列最核心就是这个循环
int64_t TimeoutQueue::runInternal(int64_t now, bool onceOnly) {
auto& byExpiration = timeouts_.get<BY_EXPIRATION>();
int64_t nextExp;
do {
const auto end = byExpiration.upper_bound(now);
std::vector<Event> expired;
std::move(byExpiration.begin(), end, std::back_inserter(expired));
byExpiration.erase(byExpiration.begin(), end);
for (const auto& event : expired) {
// Reinsert if repeating, do this before executing callbacks
// so the callbacks have a chance to call erase
if (event.repeatInterval >= 0) {
timeouts_.insert({event.id,
now + event.repeatInterval,
event.repeatInterval,
event.callback});
}
}
// Call callbacks
for (const auto& event : expired) {
event.callback(event.id, now);
}
nextExp = nextExpiration();
} while (!onceOnly && nextExp <= now);
return nextExp;
}
先找到所有时间戳的结合体,然后判断和执行回调