使用Boost ICL查找范围包含点的所有对象

Using Boost ICL to Find All Objects Whose Range Contains a Point

本文关键字:对象 包含点 范围 Boost ICL 查找 使用      更新时间:2023-10-16

给定一个对象列表L,每个对象包含一个添加的时间、一个删除的时间、一个名称和一些其他字段。给定时间T,我想返回一个列表,该列表只包含来自L的对象,其中T落在对象的添加时间和删除时间之间(另外,我想同时搜索特定名称的所有对象,但如果使事情复杂化,则没有必要)。我该如何使用Boost的ICL呢?

假设你的对象看起来像

struct record {
    std::string name;
    using ptime = boost::posix_time::ptime;
    ptime added, removed;
};

现在,让我们添加一个方便的方法,以便我们可以更轻松地处理时间间隔:

    icl::interval<ptime>::interval_type validity() const { 
        icl::interval<ptime> x;
        return x.right_open(added, removed);
    }

一个简单的测试程序是这样的:

int main()
{
    ptime const start(day_clock::local_day(), { });
    std::vector<record> L {
        { "long"     , start + hours(77) , start + days(7) }   ,
        { "medium"   , start + hours(200), start + hours(236) },
        { "short"    , start + hours(220), start + hours(226) },
        { "ephemeral", start + hours(100), start + hours(101) },
    };
    for (ptime T = start; T <= (start + days(10)); T += hours(6))
    {
        std::cout << "nT:" << T << "t";
        std::ostream_iterator<record> out(std::cout, ";");
        std::copy_if(L.begin(), L.end(), out, [T](record const& r) { return icl::contains(r.validity(), T); });
    }
}

在10天的范围内迭代时间点T,以6小时为步长,并打印L中匹配的对象,参见Live On Coliru

T:2014-Jun-06 00:00:00  
T:2014-Jun-06 06:00:00  
T:2014-Jun-06 12:00:00  
T:2014-Jun-06 18:00:00  
T:2014-Jun-07 00:00:00  
T:2014-Jun-07 06:00:00  
T:2014-Jun-07 12:00:00  
T:2014-Jun-07 18:00:00  
T:2014-Jun-08 00:00:00  
T:2014-Jun-08 06:00:00  
T:2014-Jun-08 12:00:00  
T:2014-Jun-08 18:00:00  
T:2014-Jun-09 00:00:00  
T:2014-Jun-09 06:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-09 12:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-09 18:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-10 00:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-10 06:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-10 12:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-10 18:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-11 00:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-11 06:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-11 12:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-11 18:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-12 00:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-12 06:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-12 12:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-12 18:00:00  {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
T:2014-Jun-13 00:00:00  
T:2014-Jun-13 06:00:00  
T:2014-Jun-13 12:00:00  
T:2014-Jun-13 18:00:00  
T:2014-Jun-14 00:00:00  
T:2014-Jun-14 06:00:00  
T:2014-Jun-14 12:00:00  {medium, 2014-Jun-14 08:00:00, 2014-Jun-15 20:00:00};
T:2014-Jun-14 18:00:00  {medium, 2014-Jun-14 08:00:00, 2014-Jun-15 20:00:00};
T:2014-Jun-15 00:00:00  {medium, 2014-Jun-14 08:00:00, 2014-Jun-15 20:00:00};
T:2014-Jun-15 06:00:00  {medium, 2014-Jun-14 08:00:00, 2014-Jun-15 20:00:00};{short, 2014-Jun-15 04:00:00, 2014-Jun-15 10:00:00};
T:2014-Jun-15 12:00:00  {medium, 2014-Jun-14 08:00:00, 2014-Jun-15 20:00:00};
T:2014-Jun-15 18:00:00  {medium, 2014-Jun-14 08:00:00, 2014-Jun-15 20:00:00};
T:2014-Jun-16 00:00:00  

可以看到,"ephemeral"太短了,使用这种方法完全忽略了它!您可能希望遍历插槽中的时间,而不是时间点逐步:

for (auto Slot = icl::interval<ptime>::right_open(start, start + hours(6));
     Slot.lower() <= (start + days(10)); 
     Slot = icl::interval<ptime>::right_open(Slot.upper(), Slot.upper() + hours(6)))
{
    std::cout << "nSlot:" << Slot << "t";
    std::ostream_iterator<record> out(std::cout, ";");
    std::copy_if(L.begin(), L.end(), out, [Slot](record const& r) { return icl::intersects(Slot, r.validity()); });
}

看到Live On Coliru也是,并观察"ephemeral"如何不再错过:

...
Slot:[2014-Jun-09 18:00:00,2014-Jun-10 00:00:00)    {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
Slot:[2014-Jun-10 00:00:00,2014-Jun-10 06:00:00)    {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};{ephemeral, 2014-Jun-10 04:00:00, 2014-Jun-10 05:00:00};
Slot:[2014-Jun-10 06:00:00,2014-Jun-10 12:00:00)    {long, 2014-Jun-09 05:00:00, 2014-Jun-13 00:00:00};
...