Fixed OS X build

This commit is contained in:
Daniel Wolf 2016-08-09 22:31:16 +02:00 committed by Daniel Wolf
parent ce11e59c04
commit 16892ae991
18 changed files with 220 additions and 172 deletions

View File

@ -116,6 +116,9 @@ set(webRTCFiles
) )
add_library(webRTC ${webRTCFiles}) add_library(webRTC ${webRTCFiles})
target_compile_options(webRTC PRIVATE ${disableWarningsFlags}) target_compile_options(webRTC PRIVATE ${disableWarningsFlags})
if (NOT WIN32)
target_compile_definitions(webRTC PRIVATE WEBRTC_POSIX)
endif()
set_target_properties(webRTC PROPERTIES FOLDER lib) set_target_properties(webRTC PROPERTIES FOLDER lib)
# ... Flite # ... Flite
@ -242,6 +245,7 @@ set(TEST_FILES
tests/g2pTests.cpp tests/g2pTests.cpp
tests/LazyTests.cpp tests/LazyTests.cpp
src/stringTools.cpp src/stringTools.h src/stringTools.cpp src/stringTools.h
src/platformTools.cpp src/platformTools.h
src/Timeline.h src/Timeline.h
src/TimeRange.cpp src/TimeRange.h src/TimeRange.cpp src/TimeRange.h
src/centiseconds.cpp src/centiseconds.h src/centiseconds.cpp src/centiseconds.h
@ -254,7 +258,7 @@ set(TEST_FILES
src/Lazy.h src/Lazy.h
) )
add_executable(runTests ${TEST_FILES}) add_executable(runTests ${TEST_FILES})
target_link_libraries(runTests gtest gmock gmock_main flite cppFormat) target_link_libraries(runTests ${Boost_LIBRARIES} gtest gmock gmock_main flite cppFormat)
set(CPACK_PACKAGE_NAME ${appName}) set(CPACK_PACKAGE_NAME ${appName})
string(REPLACE " " "-" CPACK_PACKAGE_NAME "${CPACK_PACKAGE_NAME}") string(REPLACE " " "-" CPACK_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")

View File

@ -37,7 +37,7 @@ std::vector<Timed<Shape>> dummyShapeIfEmpty(const Timeline<Shape>& shapes) {
std::copy(shapes.begin(), shapes.end(), std::back_inserter(result)); std::copy(shapes.begin(), shapes.end(), std::back_inserter(result));
if (result.empty()) { if (result.empty()) {
// Add zero-length empty mouth // Add zero-length empty mouth
result.push_back(Timed<Shape>(0cs, 0cs, Shape::A)); result.push_back(Timed<Shape>(0_cs, 0_cs, Shape::A));
} }
return result; return result;
} }

View File

@ -6,6 +6,7 @@
#include <list> #include <list>
#include <vector> #include <vector>
#include <mutex> #include <mutex>
#include <string>
class ProgressSink { class ProgressSink {
public: public:

View File

@ -27,15 +27,15 @@ bool VisemeOption::operator!=(const VisemeOption& rhs) const {
} }
Viseme::Viseme(const VisemeOption& option) : Viseme::Viseme(const VisemeOption& option) :
options{ { 0cs, option } } options{ { 0_cs, option } }
{} {}
Viseme::Viseme(const VisemeOption& option1, centiseconds threshold, const VisemeOption& option2) : Viseme::Viseme(const VisemeOption& option1, centiseconds threshold, const VisemeOption& option2) :
options{ { 0cs, option1 }, { threshold, option2 } } options{ { 0_cs, option1 }, { threshold, option2 } }
{} {}
Viseme::Viseme(const VisemeOption& option1, centiseconds threshold1, const VisemeOption& option2, centiseconds threshold2, const VisemeOption& option3) : Viseme::Viseme(const VisemeOption& option1, centiseconds threshold1, const VisemeOption& option2, centiseconds threshold2, const VisemeOption& option3) :
options{ { 0cs, option1 },{ threshold1, option2 }, { threshold2, option3 } } options{ { 0_cs, option1 },{ threshold1, option2 }, { threshold2, option3 } }
{} {}
Shape Viseme::getShape(centiseconds duration, Shape context) const { Shape Viseme::getShape(centiseconds duration, Shape context) const {

View File

@ -4,7 +4,7 @@
using std::invalid_argument; using std::invalid_argument;
TimeRange AudioClip::getTruncatedRange() const { TimeRange AudioClip::getTruncatedRange() const {
return TimeRange(0cs, centiseconds(100 * size() / getSampleRate())); return TimeRange(0_cs, centiseconds(100 * size() / getSampleRate()));
} }
class SafeSampleReader { class SafeSampleReader {

View File

@ -1,4 +1,5 @@
#include "DCOffset.h" #include "DCOffset.h"
#include <cmath>
using std::unique_ptr; using std::unique_ptr;
using std::make_unique; using std::make_unique;

View File

@ -2,6 +2,7 @@
#include <string.h> #include <string.h>
#include "WaveFileReader.h" #include "WaveFileReader.h"
#include "ioTools.h" #include "ioTools.h"
#include "platformTools.h"
using std::runtime_error; using std::runtime_error;
using fmt::format; using fmt::format;
@ -46,9 +47,7 @@ std::ifstream openFile(path filePath) {
return std::move(file); return std::move(file);
} catch (const std::ifstream::failure&) { } catch (const std::ifstream::failure&) {
char message[256]; throw runtime_error(errorNumberToString(errno));
strerror_s(message, sizeof message, errno);
throw runtime_error(message);
} }
} }

View File

@ -35,7 +35,7 @@ BoundedTimeline<void> webRtcDetectVoiceActivity(const AudioClip& audioClip, Prog
// Detect activity // Detect activity
BoundedTimeline<void> activity(audioClip.getTruncatedRange()); BoundedTimeline<void> activity(audioClip.getTruncatedRange());
centiseconds time = 0cs; centiseconds time = 0_cs;
const size_t bufferCapacity = audioClip.getSampleRate() / 100; const size_t bufferCapacity = audioClip.getSampleRate() / 100;
auto processBuffer = [&](const vector<int16_t>& buffer) { auto processBuffer = [&](const vector<int16_t>& buffer) {
// WebRTC is picky regarding buffer size // WebRTC is picky regarding buffer size
@ -46,9 +46,9 @@ BoundedTimeline<void> webRtcDetectVoiceActivity(const AudioClip& audioClip, Prog
bool isActive = result != 0; bool isActive = result != 0;
if (isActive) { if (isActive) {
activity.set(time, time + 1cs); activity.set(time, time + 1_cs);
} }
time += 1cs; time += 1_cs;
}; };
process16bitAudioClip(audioClip, processBuffer, bufferCapacity, pass1ProgressSink); process16bitAudioClip(audioClip, processBuffer, bufferCapacity, pass1ProgressSink);
@ -58,8 +58,8 @@ BoundedTimeline<void> webRtcDetectVoiceActivity(const AudioClip& audioClip, Prog
if (!activity.empty()) { if (!activity.empty()) {
TimeRange firstActivity = activity.begin()->getTimeRange(); TimeRange firstActivity = activity.begin()->getTimeRange();
activity.clear(firstActivity); activity.clear(firstActivity);
unique_ptr<AudioClip> streamStart = audioClip.clone() | segment(TimeRange(0cs, firstActivity.getEnd())); unique_ptr<AudioClip> streamStart = audioClip.clone() | segment(TimeRange(0_cs, firstActivity.getEnd()));
time = 0cs; time = 0_cs;
process16bitAudioClip(*streamStart, processBuffer, bufferCapacity, pass2ProgressSink); process16bitAudioClip(*streamStart, processBuffer, bufferCapacity, pass2ProgressSink);
} }

View File

@ -1,17 +1,15 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <ostream>
typedef std::chrono::duration<int, std::centi> centiseconds; typedef std::chrono::duration<int, std::centi> centiseconds;
std::ostream& operator <<(std::ostream& stream, const centiseconds cs); std::ostream& operator <<(std::ostream& stream, const centiseconds cs);
// I know user-defined literals should start with an underscore.
// But chances are slim the standard will introduce a "cs" literal
// with a different meaning than "centiseconds".
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4455) #pragma warning(disable: 4455)
inline constexpr centiseconds operator ""cs(unsigned long long cs) { inline constexpr centiseconds operator "" _cs(unsigned long long cs) {
return centiseconds(cs); return centiseconds(cs);
} }
#pragma warning(pop) #pragma warning(pop)

View File

@ -2,12 +2,15 @@
#include <tools.h> #include <tools.h>
#include <iostream> #include <iostream>
#include <atomic> #include <atomic>
#include <thread>
#include <unordered_map>
using namespace logging; using namespace logging;
using std::string; using std::string;
using std::vector; using std::vector;
using std::shared_ptr; using std::shared_ptr;
using std::lock_guard; using std::lock_guard;
using std::unordered_map;
LevelConverter& LevelConverter::get() { LevelConverter& LevelConverter::get() {
static LevelConverter converter; static LevelConverter converter;
@ -37,15 +40,29 @@ std::istream& logging::operator>>(std::istream& stream, Level& value) {
return LevelConverter::get().read(stream, value); return LevelConverter::get().read(stream, value);
} }
// Returns an int representing the current thread.
// This used to be a simple thread_local variable, but Xcode doesn't support that yet
int getThreadCounter() {
using thread_id = std::thread::id;
static std::mutex counterMutex;
lock_guard<std::mutex> lock(counterMutex);
static unordered_map<thread_id, int> threadCounters;
static int lastThreadId = 0;
thread_id threadId = std::this_thread::get_id();
if (threadCounters.find(threadId) == threadCounters.end()) {
threadCounters.insert({threadId, ++lastThreadId});
}
return threadCounters.find(threadId)->second;
}
Entry::Entry(Level level, const string& message) : Entry::Entry(Level level, const string& message) :
level(level), level(level),
message(message) message(message)
{ {
time(&timestamp); time(&timestamp);
this->threadCounter = getThreadCounter();
static std::atomic<int> lastThreadId = 0;
thread_local int threadCounter = ++lastThreadId;
this->threadCounter = threadCounter;
} }
string SimpleConsoleFormatter::format(const Entry& entry) { string SimpleConsoleFormatter::format(const Entry& entry) {

View File

@ -28,21 +28,21 @@ constexpr Shape X = Shape::X;
Timeline<Viseme> animate(optional<Phone> phone, centiseconds duration, centiseconds previousPhoneDuration) { Timeline<Viseme> animate(optional<Phone> phone, centiseconds duration, centiseconds previousPhoneDuration) {
auto single = [&](Viseme viseme) { auto single = [&](Viseme viseme) {
return Timeline<Viseme>{ return Timeline<Viseme>{
{ 0cs, duration, viseme } { 0_cs, duration, viseme }
}; };
}; };
auto diphtong = [&](Viseme first, Viseme second) { auto diphtong = [&](Viseme first, Viseme second) {
centiseconds firstDuration = duration_cast<centiseconds>(duration * 0.6); centiseconds firstDuration = duration_cast<centiseconds>(duration * 0.6);
return Timeline<Viseme>{ return Timeline<Viseme>{
{ 0cs, firstDuration, first }, { 0_cs, firstDuration, first },
{ firstDuration, duration, second } { firstDuration, duration, second }
}; };
}; };
auto bilabialStop = [&]() { auto bilabialStop = [&]() {
centiseconds maxDuration = 12cs; centiseconds maxDuration = 12_cs;
centiseconds leftOverlap = clamp(previousPhoneDuration / 2, 4cs, maxDuration); centiseconds leftOverlap = clamp(previousPhoneDuration / 2, 4_cs, maxDuration);
centiseconds rightOverlap = min(duration, maxDuration - leftOverlap); centiseconds rightOverlap = min(duration, maxDuration - leftOverlap);
return Timeline<Viseme>{ return Timeline<Viseme>{
{ -leftOverlap, rightOverlap, { A } }, { -leftOverlap, rightOverlap, { A } },
@ -61,7 +61,7 @@ Timeline<Viseme> animate(optional<Phone> phone, centiseconds duration, centiseco
case Phone::EH: return single({ C }); case Phone::EH: return single({ C });
case Phone::IH: return single({ B }); case Phone::IH: return single({ B });
case Phone::UH: return single({ E }); case Phone::UH: return single({ E });
case Phone::AH: return single({ { B, C, D, E, F }, 6cs, { C } }); // Heuristic: < 6cs is schwa case Phone::AH: return single({ { B, C, D, E, F }, 6_cs, { C } }); // Heuristic: < 6_cs is schwa
case Phone::AE: return single({ D }); case Phone::AE: return single({ D });
case Phone::EY: return diphtong({ C }, { B }); case Phone::EY: return diphtong({ C }, { B });
case Phone::AY: return diphtong({ D }, { B }); case Phone::AY: return diphtong({ D }, { B });
@ -119,8 +119,8 @@ optional<pair<Shape, TweenTiming>> getTween(Shape first, Shape second) {
} }
Timeline<Shape> createTweens(ContinuousTimeline<Shape> shapes) { Timeline<Shape> createTweens(ContinuousTimeline<Shape> shapes) {
centiseconds minTweenDuration = 4cs; centiseconds minTweenDuration = 4_cs;
centiseconds maxTweenDuration = 10cs; centiseconds maxTweenDuration = 10_cs;
Timeline<Shape> tweens; Timeline<Shape> tweens;
@ -171,7 +171,7 @@ Timeline<Shape> animatePauses(const ContinuousTimeline<Shape>& shapes) {
for (const auto& timedShape : shapes) { for (const auto& timedShape : shapes) {
if (timedShape.getValue() != X) continue; if (timedShape.getValue() != X) continue;
const centiseconds maxPausedOpenMouthDuration = 35cs; const centiseconds maxPausedOpenMouthDuration = 35_cs;
const TimeRange timeRange = timedShape.getTimeRange(); const TimeRange timeRange = timedShape.getTimeRange();
if (timeRange.getLength() <= maxPausedOpenMouthDuration) { if (timeRange.getLength() <= maxPausedOpenMouthDuration) {
result.set(timeRange, B); result.set(timeRange, B);
@ -183,9 +183,9 @@ Timeline<Shape> animatePauses(const ContinuousTimeline<Shape>& shapes) {
if (pause.getValue() != X) return; if (pause.getValue() != X) return;
centiseconds lastLength = last.getTimeRange().getLength(); centiseconds lastLength = last.getTimeRange().getLength();
const centiseconds minOpenDuration = 20cs; const centiseconds minOpenDuration = 20_cs;
if (isClosed(secondLast.getValue()) && !isClosed(last.getValue()) && lastLength < minOpenDuration) { if (isClosed(secondLast.getValue()) && !isClosed(last.getValue()) && lastLength < minOpenDuration) {
const centiseconds minSpillDuration = 20cs; const centiseconds minSpillDuration = 20_cs;
centiseconds spillDuration = std::min(minSpillDuration, pause.getTimeRange().getLength()); centiseconds spillDuration = std::min(minSpillDuration, pause.getTimeRange().getLength());
result.set(pause.getStart(), pause.getStart() + spillDuration, B); result.set(pause.getStart(), pause.getStart() + spillDuration, B);
} }
@ -203,7 +203,7 @@ ContinuousTimeline<Shape> animate(const BoundedTimeline<Phone> &phones) {
// Create timeline of visemes // Create timeline of visemes
ContinuousTimeline<Viseme> visemes(phones.getRange(), { X }); ContinuousTimeline<Viseme> visemes(phones.getRange(), { X });
centiseconds previousPhoneDuration = 0cs; centiseconds previousPhoneDuration = 0_cs;
for (const auto& timedPhone : continuousPhones) { for (const auto& timedPhone : continuousPhones) {
// Animate one phone // Animate one phone
optional<Phone> phone = timedPhone.getValue(); optional<Phone> phone = timedPhone.getValue();

View File

@ -140,3 +140,25 @@ path getTempFilePath() {
string fileName = to_string(generateUuid()); string fileName = to_string(generateUuid());
return tempDirectory / fileName; return tempDirectory / fileName;
} }
std::tm getLocalTime(const time_t& time) {
// Xcode doesn't support localtime_s.
tm timeInfo;
#if (BOOST_OS_MACOS)
localtime_r(&time, &timeInfo);
#else
localtime_s(&timeInfo, &time);
#endif
return timeInfo;
}
std::string errorNumberToString(int errorNumber) {
// Xcode doesn't support strerror_s.
char message[256];
#if (BOOST_OS_MACOS)
strerror_r(errorNumber, message, sizeof message);
#else
strerror_s(message, sizeof message, errorNumber);
#endif
return message;
}

View File

@ -1,7 +1,12 @@
#pragma once #pragma once
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <ctime>
#include <string>
boost::filesystem::path getBinPath(); boost::filesystem::path getBinPath();
boost::filesystem::path getBinDirectory(); boost::filesystem::path getBinDirectory();
boost::filesystem::path getTempFilePath(); boost::filesystem::path getTempFilePath();
std::tm getLocalTime(const time_t& time);
std::string errorNumberToString(int errorNumber);

View File

@ -2,5 +2,6 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <string>
std::vector<std::string> tokenizeText(const std::u32string& text, std::function<bool(const std::string&)> dictionaryContains); std::vector<std::string> tokenizeText(const std::u32string& text, std::function<bool(const std::string&)> dictionaryContains);

View File

@ -1,4 +1,5 @@
#include "tools.h" #include "tools.h"
#include "platformTools.h"
#include <format.h> #include <format.h>
#include <chrono> #include <chrono>
#include <vector> #include <vector>
@ -11,8 +12,7 @@ string formatDuration(duration<double> seconds) {
} }
string formatTime(time_t time, const string& format) { string formatTime(time_t time, const string& format) {
tm timeInfo; tm timeInfo = getLocalTime(time);
localtime_s(&timeInfo, &time);
std::vector<char> buffer(20); std::vector<char> buffer(20);
bool success = false; bool success = false;
while (!success) { while (!success) {

View File

@ -7,16 +7,16 @@ using boost::optional;
using std::initializer_list; using std::initializer_list;
TEST(BoundedTimeline, constructors_initializeState) { TEST(BoundedTimeline, constructors_initializeState) {
TimeRange range(-5cs, 55cs); TimeRange range(-5_cs, 55_cs);
auto args = { auto args = {
Timed<int>(-10cs, 30cs, 1), Timed<int>(-10_cs, 30_cs, 1),
Timed<int>(10cs, 40cs, 2), Timed<int>(10_cs, 40_cs, 2),
Timed<int>(50cs, 60cs, 3) Timed<int>(50_cs, 60_cs, 3)
}; };
auto expected = { auto expected = {
Timed<int>(-5cs, 10cs, 1), Timed<int>(-5_cs, 10_cs, 1),
Timed<int>(10cs, 40cs, 2), Timed<int>(10_cs, 40_cs, 2),
Timed<int>(50cs, 55cs, 3) Timed<int>(50_cs, 55_cs, 3)
}; };
EXPECT_THAT( EXPECT_THAT(
BoundedTimeline<int>(range, args.begin(), args.end()), BoundedTimeline<int>(range, args.begin(), args.end()),
@ -29,67 +29,67 @@ TEST(BoundedTimeline, constructors_initializeState) {
} }
TEST(BoundedTimeline, empty) { TEST(BoundedTimeline, empty) {
BoundedTimeline<int> empty(TimeRange(0cs, 10cs)); BoundedTimeline<int> empty(TimeRange(0_cs, 10_cs));
EXPECT_TRUE(empty.empty()); EXPECT_TRUE(empty.empty());
EXPECT_THAT(empty, IsEmpty()); EXPECT_THAT(empty, IsEmpty());
BoundedTimeline<int> nonEmpty(TimeRange(0cs, 10cs), { Timed<int>(1cs, 2cs, 1) }); BoundedTimeline<int> nonEmpty(TimeRange(0_cs, 10_cs), { Timed<int>(1_cs, 2_cs, 1) });
EXPECT_FALSE(nonEmpty.empty()); EXPECT_FALSE(nonEmpty.empty());
EXPECT_THAT(nonEmpty, Not(IsEmpty())); EXPECT_THAT(nonEmpty, Not(IsEmpty()));
} }
TEST(BoundedTimeline, getRange) { TEST(BoundedTimeline, getRange) {
TimeRange range(0cs, 10cs); TimeRange range(0_cs, 10_cs);
BoundedTimeline<int> empty(range); BoundedTimeline<int> empty(range);
EXPECT_EQ(range, empty.getRange()); EXPECT_EQ(range, empty.getRange());
BoundedTimeline<int> nonEmpty(range, { Timed<int>(1cs, 2cs, 1) }); BoundedTimeline<int> nonEmpty(range, { Timed<int>(1_cs, 2_cs, 1) });
EXPECT_EQ(range, nonEmpty.getRange()); EXPECT_EQ(range, nonEmpty.getRange());
} }
TEST(BoundedTimeline, setAndClear) { TEST(BoundedTimeline, setAndClear) {
TimeRange range(0cs, 10cs); TimeRange range(0_cs, 10_cs);
BoundedTimeline<int> timeline(range); BoundedTimeline<int> timeline(range);
// Out of range // Out of range
timeline.set(-10cs, -1cs, 1); timeline.set(-10_cs, -1_cs, 1);
timeline.set(TimeRange(-5cs, -1cs), 2); timeline.set(TimeRange(-5_cs, -1_cs), 2);
timeline.set(Timed<int>(10cs, 15cs, 3)); timeline.set(Timed<int>(10_cs, 15_cs, 3));
// Overlapping // Overlapping
timeline.set(-2cs, 5cs, 4); timeline.set(-2_cs, 5_cs, 4);
timeline.set(TimeRange(-1cs, 1cs), 5); timeline.set(TimeRange(-1_cs, 1_cs), 5);
timeline.set(Timed<int>(8cs, 12cs, 6)); timeline.set(Timed<int>(8_cs, 12_cs, 6));
// Within // Within
timeline.set(5cs, 9cs, 7); timeline.set(5_cs, 9_cs, 7);
timeline.set(TimeRange(6cs, 7cs), 8); timeline.set(TimeRange(6_cs, 7_cs), 8);
timeline.set(Timed<int>(7cs, 8cs, 9)); timeline.set(Timed<int>(7_cs, 8_cs, 9));
auto expected = { auto expected = {
Timed<int>(0cs, 1cs, 5), Timed<int>(0_cs, 1_cs, 5),
Timed<int>(1cs, 5cs, 4), Timed<int>(1_cs, 5_cs, 4),
Timed<int>(5cs, 6cs, 7), Timed<int>(5_cs, 6_cs, 7),
Timed<int>(6cs, 7cs, 8), Timed<int>(6_cs, 7_cs, 8),
Timed<int>(7cs, 8cs, 9), Timed<int>(7_cs, 8_cs, 9),
Timed<int>(8cs, 9cs, 7), Timed<int>(8_cs, 9_cs, 7),
Timed<int>(9cs, 10cs, 6) Timed<int>(9_cs, 10_cs, 6)
}; };
EXPECT_THAT(timeline, ElementsAreArray(expected)); EXPECT_THAT(timeline, ElementsAreArray(expected));
} }
TEST(BoundedTimeline, shift) { TEST(BoundedTimeline, shift) {
BoundedTimeline<int> timeline(TimeRange(0cs, 10cs), { { 1cs, 2cs, 1 }, { 2cs, 5cs, 2 }, { 7cs, 9cs, 3 } }); BoundedTimeline<int> timeline(TimeRange(0_cs, 10_cs), { { 1_cs, 2_cs, 1 }, { 2_cs, 5_cs, 2 }, { 7_cs, 9_cs, 3 } });
BoundedTimeline<int> expected(TimeRange(2cs, 12cs), { { 3cs, 4cs, 1 }, { 4cs, 7cs, 2 }, { 9cs, 11cs, 3 } }); BoundedTimeline<int> expected(TimeRange(2_cs, 12_cs), { { 3_cs, 4_cs, 1 }, { 4_cs, 7_cs, 2 }, { 9_cs, 11_cs, 3 } });
timeline.shift(2cs); timeline.shift(2_cs);
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
TEST(BoundedTimeline, equality) { TEST(BoundedTimeline, equality) {
vector<BoundedTimeline<int>> timelines = { vector<BoundedTimeline<int>> timelines = {
BoundedTimeline<int>(TimeRange(0cs, 10cs)), BoundedTimeline<int>(TimeRange(0_cs, 10_cs)),
BoundedTimeline<int>(TimeRange(0cs, 10cs), { { 1cs, 2cs, 1 } }), BoundedTimeline<int>(TimeRange(0_cs, 10_cs), { { 1_cs, 2_cs, 1 } }),
BoundedTimeline<int>(TimeRange(1cs, 10cs), { { 1cs, 2cs, 1 } }) BoundedTimeline<int>(TimeRange(1_cs, 10_cs), { { 1_cs, 2_cs, 1 } })
}; };
for (size_t i = 0; i < timelines.size(); ++i) { for (size_t i = 0; i < timelines.size(); ++i) {

View File

@ -7,18 +7,18 @@ using boost::optional;
using std::initializer_list; using std::initializer_list;
TEST(ContinuousTimeline, constructors_initializeState) { TEST(ContinuousTimeline, constructors_initializeState) {
TimeRange range(-5cs, 55cs); TimeRange range(-5_cs, 55_cs);
int defaultValue = -1; int defaultValue = -1;
auto args = { auto args = {
Timed<int>(-10cs, 30cs, 1), Timed<int>(-10_cs, 30_cs, 1),
Timed<int>(10cs, 40cs, 2), Timed<int>(10_cs, 40_cs, 2),
Timed<int>(50cs, 60cs, 3) Timed<int>(50_cs, 60_cs, 3)
}; };
auto expected = { auto expected = {
Timed<int>(-5cs, 10cs, 1), Timed<int>(-5_cs, 10_cs, 1),
Timed<int>(10cs, 40cs, 2), Timed<int>(10_cs, 40_cs, 2),
Timed<int>(40cs, 50cs, defaultValue), Timed<int>(40_cs, 50_cs, defaultValue),
Timed<int>(50cs, 55cs, 3) Timed<int>(50_cs, 55_cs, 3)
}; };
EXPECT_THAT( EXPECT_THAT(
ContinuousTimeline<int>(range, defaultValue, args.begin(), args.end()), ContinuousTimeline<int>(range, defaultValue, args.begin(), args.end()),
@ -31,65 +31,65 @@ TEST(ContinuousTimeline, constructors_initializeState) {
} }
TEST(ContinuousTimeline, empty) { TEST(ContinuousTimeline, empty) {
ContinuousTimeline<int> empty(TimeRange(10cs, 10cs), -1); ContinuousTimeline<int> empty(TimeRange(10_cs, 10_cs), -1);
EXPECT_TRUE(empty.empty()); EXPECT_TRUE(empty.empty());
EXPECT_THAT(empty, IsEmpty()); EXPECT_THAT(empty, IsEmpty());
ContinuousTimeline<int> nonEmpty1(TimeRange(0cs, 10cs), -1); ContinuousTimeline<int> nonEmpty1(TimeRange(0_cs, 10_cs), -1);
EXPECT_FALSE(nonEmpty1.empty()); EXPECT_FALSE(nonEmpty1.empty());
EXPECT_THAT(nonEmpty1, Not(IsEmpty())); EXPECT_THAT(nonEmpty1, Not(IsEmpty()));
ContinuousTimeline<int> nonEmpty2(TimeRange(0cs, 10cs), -1, { Timed<int>(1cs, 2cs, 1) }); ContinuousTimeline<int> nonEmpty2(TimeRange(0_cs, 10_cs), -1, { Timed<int>(1_cs, 2_cs, 1) });
EXPECT_FALSE(nonEmpty2.empty()); EXPECT_FALSE(nonEmpty2.empty());
EXPECT_THAT(nonEmpty2, Not(IsEmpty())); EXPECT_THAT(nonEmpty2, Not(IsEmpty()));
} }
TEST(ContinuousTimeline, setAndClear) { TEST(ContinuousTimeline, setAndClear) {
TimeRange range(0cs, 10cs); TimeRange range(0_cs, 10_cs);
int defaultValue = -1; int defaultValue = -1;
ContinuousTimeline<int> timeline(range, defaultValue); ContinuousTimeline<int> timeline(range, defaultValue);
// Out of range // Out of range
timeline.set(-10cs, -1cs, 1); timeline.set(-10_cs, -1_cs, 1);
timeline.set(TimeRange(-5cs, -1cs), 2); timeline.set(TimeRange(-5_cs, -1_cs), 2);
timeline.set(Timed<int>(10cs, 15cs, 3)); timeline.set(Timed<int>(10_cs, 15_cs, 3));
// Overlapping // Overlapping
timeline.set(-2cs, 3cs, 4); timeline.set(-2_cs, 3_cs, 4);
timeline.set(TimeRange(-1cs, 1cs), 5); timeline.set(TimeRange(-1_cs, 1_cs), 5);
timeline.set(Timed<int>(8cs, 12cs, 6)); timeline.set(Timed<int>(8_cs, 12_cs, 6));
// Within // Within
timeline.set(5cs, 9cs, 7); timeline.set(5_cs, 9_cs, 7);
timeline.set(TimeRange(6cs, 7cs), 8); timeline.set(TimeRange(6_cs, 7_cs), 8);
timeline.set(Timed<int>(7cs, 8cs, 9)); timeline.set(Timed<int>(7_cs, 8_cs, 9));
auto expected = { auto expected = {
Timed<int>(0cs, 1cs, 5), Timed<int>(0_cs, 1_cs, 5),
Timed<int>(1cs, 3cs, 4), Timed<int>(1_cs, 3_cs, 4),
Timed<int>(3cs, 5cs, defaultValue), Timed<int>(3_cs, 5_cs, defaultValue),
Timed<int>(5cs, 6cs, 7), Timed<int>(5_cs, 6_cs, 7),
Timed<int>(6cs, 7cs, 8), Timed<int>(6_cs, 7_cs, 8),
Timed<int>(7cs, 8cs, 9), Timed<int>(7_cs, 8_cs, 9),
Timed<int>(8cs, 9cs, 7), Timed<int>(8_cs, 9_cs, 7),
Timed<int>(9cs, 10cs, 6) Timed<int>(9_cs, 10_cs, 6)
}; };
EXPECT_THAT(timeline, ElementsAreArray(expected)); EXPECT_THAT(timeline, ElementsAreArray(expected));
} }
TEST(ContinuousTimeline, shift) { TEST(ContinuousTimeline, shift) {
ContinuousTimeline<int> timeline(TimeRange(0cs, 10cs), -1, { { 1cs, 2cs, 1 },{ 2cs, 5cs, 2 },{ 7cs, 9cs, 3 } }); ContinuousTimeline<int> timeline(TimeRange(0_cs, 10_cs), -1, { { 1_cs, 2_cs, 1 },{ 2_cs, 5_cs, 2 },{ 7_cs, 9_cs, 3 } });
ContinuousTimeline<int> expected(TimeRange(2cs, 12cs), -1, { { 3cs, 4cs, 1 },{ 4cs, 7cs, 2 },{ 9cs, 11cs, 3 } }); ContinuousTimeline<int> expected(TimeRange(2_cs, 12_cs), -1, { { 3_cs, 4_cs, 1 },{ 4_cs, 7_cs, 2 },{ 9_cs, 11_cs, 3 } });
timeline.shift(2cs); timeline.shift(2_cs);
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
TEST(ContinuousTimeline, equality) { TEST(ContinuousTimeline, equality) {
vector<ContinuousTimeline<int>> timelines = { vector<ContinuousTimeline<int>> timelines = {
ContinuousTimeline<int>(TimeRange(0cs, 10cs), -1), ContinuousTimeline<int>(TimeRange(0_cs, 10_cs), -1),
ContinuousTimeline<int>(TimeRange(0cs, 10cs), 1), ContinuousTimeline<int>(TimeRange(0_cs, 10_cs), 1),
ContinuousTimeline<int>(TimeRange(0cs, 10cs), -1, { { 1cs, 2cs, 1 } }), ContinuousTimeline<int>(TimeRange(0_cs, 10_cs), -1, { { 1_cs, 2_cs, 1 } }),
ContinuousTimeline<int>(TimeRange(1cs, 10cs), -1, { { 1cs, 2cs, 1 } }) ContinuousTimeline<int>(TimeRange(1_cs, 10_cs), -1, { { 1_cs, 2_cs, 1 } })
}; };
for (size_t i = 0; i < timelines.size(); ++i) { for (size_t i = 0; i < timelines.size(); ++i) {

View File

@ -11,14 +11,14 @@ using boost::none;
TEST(Timeline, constructors_initializeState) { TEST(Timeline, constructors_initializeState) {
auto args = { auto args = {
Timed<int>(-10cs, 30cs, 1), Timed<int>(-10_cs, 30_cs, 1),
Timed<int>(10cs, 40cs, 2), Timed<int>(10_cs, 40_cs, 2),
Timed<int>(50cs, 60cs, 3) Timed<int>(50_cs, 60_cs, 3)
}; };
auto expected = { auto expected = {
Timed<int>(-10cs, 10cs, 1), Timed<int>(-10_cs, 10_cs, 1),
Timed<int>(10cs, 40cs, 2), Timed<int>(10_cs, 40_cs, 2),
Timed<int>(50cs, 60cs, 3) Timed<int>(50_cs, 60_cs, 3)
}; };
EXPECT_THAT( EXPECT_THAT(
Timeline<int>(args.begin(), args.end()), Timeline<int>(args.begin(), args.end()),
@ -39,11 +39,11 @@ TEST(Timeline, empty) {
EXPECT_TRUE(empty1.empty()); EXPECT_TRUE(empty1.empty());
EXPECT_THAT(empty1, IsEmpty()); EXPECT_THAT(empty1, IsEmpty());
Timeline<int> empty2{ Timed<int>(1cs, 1cs, 1) }; Timeline<int> empty2{ Timed<int>(1_cs, 1_cs, 1) };
EXPECT_TRUE(empty2.empty()); EXPECT_TRUE(empty2.empty());
EXPECT_THAT(empty2, IsEmpty()); EXPECT_THAT(empty2, IsEmpty());
Timeline<int> nonEmpty{ Timed<int>(1cs, 2cs, 1) }; Timeline<int> nonEmpty{ Timed<int>(1_cs, 2_cs, 1) };
EXPECT_FALSE(nonEmpty.empty()); EXPECT_FALSE(nonEmpty.empty());
EXPECT_THAT(nonEmpty, Not(IsEmpty())); EXPECT_THAT(nonEmpty, Not(IsEmpty()));
} }
@ -57,39 +57,39 @@ TEST(Timeline, size) {
EXPECT_EQ(0, empty1.size()); EXPECT_EQ(0, empty1.size());
EXPECT_THAT(empty1, SizeIs(0)); EXPECT_THAT(empty1, SizeIs(0));
Timeline<int> empty2{ Timed<int>(1cs, 1cs, 1) }; Timeline<int> empty2{ Timed<int>(1_cs, 1_cs, 1) };
EXPECT_EQ(0, empty2.size()); EXPECT_EQ(0, empty2.size());
EXPECT_THAT(empty2, SizeIs(0)); EXPECT_THAT(empty2, SizeIs(0));
Timeline<int> size1{ Timed<int>(1cs, 10cs, 1) }; Timeline<int> size1{ Timed<int>(1_cs, 10_cs, 1) };
EXPECT_EQ(1, size1.size()); EXPECT_EQ(1, size1.size());
EXPECT_THAT(size1, SizeIs(1)); EXPECT_THAT(size1, SizeIs(1));
Timeline<int> size2{ Timed<int>(-10cs, 10cs, 1), Timed<int>(10cs, 11cs, 5) }; Timeline<int> size2{ Timed<int>(-10_cs, 10_cs, 1), Timed<int>(10_cs, 11_cs, 5) };
EXPECT_EQ(2, size2.size()); EXPECT_EQ(2, size2.size());
EXPECT_THAT(size2, SizeIs(2)); EXPECT_THAT(size2, SizeIs(2));
} }
TEST(Timeline, getRange) { TEST(Timeline, getRange) {
Timeline<int> empty0; Timeline<int> empty0;
EXPECT_EQ(TimeRange(0cs, 0cs), empty0.getRange()); EXPECT_EQ(TimeRange(0_cs, 0_cs), empty0.getRange());
Timeline<int> empty1{}; Timeline<int> empty1{};
EXPECT_EQ(TimeRange(0cs, 0cs), empty1.getRange()); EXPECT_EQ(TimeRange(0_cs, 0_cs), empty1.getRange());
Timeline<int> empty2{ Timed<int>(1cs, 1cs, 1) }; Timeline<int> empty2{ Timed<int>(1_cs, 1_cs, 1) };
EXPECT_EQ(TimeRange(0cs, 0cs), empty2.getRange()); EXPECT_EQ(TimeRange(0_cs, 0_cs), empty2.getRange());
Timeline<int> nonEmpty1{ Timed<int>(1cs, 10cs, 1) }; Timeline<int> nonEmpty1{ Timed<int>(1_cs, 10_cs, 1) };
EXPECT_EQ(TimeRange(1cs, 10cs), nonEmpty1.getRange()); EXPECT_EQ(TimeRange(1_cs, 10_cs), nonEmpty1.getRange());
Timeline<int> nonEmpty2{ Timed<int>(-10cs, 5cs, 1), Timed<int>(10cs, 11cs, 5) }; Timeline<int> nonEmpty2{ Timed<int>(-10_cs, 5_cs, 1), Timed<int>(10_cs, 11_cs, 5) };
EXPECT_EQ(TimeRange(-10cs, 11cs), nonEmpty2.getRange()); EXPECT_EQ(TimeRange(-10_cs, 11_cs), nonEmpty2.getRange());
} }
TEST(Timeline, iterators) { TEST(Timeline, iterators) {
Timeline<int> timeline{ Timed<int>(-5cs, 0cs, 10), Timed<int>(5cs, 15cs, 9) }; Timeline<int> timeline{ Timed<int>(-5_cs, 0_cs, 10), Timed<int>(5_cs, 15_cs, 9) };
auto expected = { Timed<int>(-5cs, 0cs, 10), Timed<int>(5cs, 15cs, 9) }; auto expected = { Timed<int>(-5_cs, 0_cs, 10), Timed<int>(5_cs, 15_cs, 9) };
EXPECT_THAT(timeline, ElementsAreArray(expected)); EXPECT_THAT(timeline, ElementsAreArray(expected));
vector<Timed<int>> reversedActual; vector<Timed<int>> reversedActual;
@ -115,9 +115,9 @@ void testFind(const Timeline<int>& timeline, FindMode findMode, const initialize
} }
TEST(Timeline, find) { TEST(Timeline, find) {
Timed<int> a = Timed<int>(1cs, 2cs, 1); Timed<int> a = Timed<int>(1_cs, 2_cs, 1);
Timed<int> b = Timed<int>(2cs, 5cs, 2); Timed<int> b = Timed<int>(2_cs, 5_cs, 2);
Timed<int> c = Timed<int>(7cs, 9cs, 3); Timed<int> c = Timed<int>(7_cs, 9_cs, 3);
Timeline<int> timeline{ a, b, c }; Timeline<int> timeline{ a, b, c };
testFind(timeline, FindMode::SampleLeft, { nullptr, nullptr, &a, &b, &b, &b, nullptr, nullptr, &c, &c, nullptr }); testFind(timeline, FindMode::SampleLeft, { nullptr, nullptr, &a, &b, &b, &b, nullptr, nullptr, &c, &c, nullptr });
@ -127,9 +127,9 @@ TEST(Timeline, find) {
} }
TEST(Timeline, get) { TEST(Timeline, get) {
Timed<int> a = Timed<int>(1cs, 2cs, 1); Timed<int> a = Timed<int>(1_cs, 2_cs, 1);
Timed<int> b = Timed<int>(2cs, 5cs, 2); Timed<int> b = Timed<int>(2_cs, 5_cs, 2);
Timed<int> c = Timed<int>(7cs, 9cs, 3); Timed<int> c = Timed<int>(7_cs, 9_cs, 3);
Timeline<int> timeline{ a, b, c }; Timeline<int> timeline{ a, b, c };
initializer_list<Timed<int>*> expectedResults = { nullptr, &a, &b, &b, &b, nullptr, nullptr, &c, &c, nullptr, nullptr }; initializer_list<Timed<int>*> expectedResults = { nullptr, &a, &b, &b, &b, nullptr, nullptr, &c, &c, nullptr, nullptr };
@ -148,39 +148,39 @@ TEST(Timeline, get) {
} }
TEST(Timeline, clear) { TEST(Timeline, clear) {
Timeline<int> original{ { 1cs, 2cs, 1 }, { 2cs, 5cs, 2 }, { 7cs, 9cs, 3 } }; Timeline<int> original{ { 1_cs, 2_cs, 1 }, { 2_cs, 5_cs, 2 }, { 7_cs, 9_cs, 3 } };
{ {
auto timeline = original; auto timeline = original;
timeline.clear(-10cs, 10cs); timeline.clear(-10_cs, 10_cs);
EXPECT_THAT(timeline, IsEmpty()); EXPECT_THAT(timeline, IsEmpty());
} }
{ {
auto timeline = original; auto timeline = original;
timeline.clear(1cs, 2cs); timeline.clear(1_cs, 2_cs);
Timeline<int> expected{ { 2cs, 5cs, 2 }, { 7cs, 9cs, 3 } }; Timeline<int> expected{ { 2_cs, 5_cs, 2 }, { 7_cs, 9_cs, 3 } };
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
{ {
auto timeline = original; auto timeline = original;
timeline.clear(3cs, 4cs); timeline.clear(3_cs, 4_cs);
Timeline<int> expected{ { 1cs, 2cs, 1 }, { 2cs, 3cs, 2 }, { 4cs, 5cs, 2}, { 7cs, 9cs, 3} }; Timeline<int> expected{ { 1_cs, 2_cs, 1 }, { 2_cs, 3_cs, 2 }, { 4_cs, 5_cs, 2}, { 7_cs, 9_cs, 3} };
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
{ {
auto timeline = original; auto timeline = original;
timeline.clear(6cs, 8cs); timeline.clear(6_cs, 8_cs);
Timeline<int> expected{ { 1cs, 2cs, 1 }, { 2cs, 5cs, 2 }, { 8cs, 9cs, 3 } }; Timeline<int> expected{ { 1_cs, 2_cs, 1 }, { 2_cs, 5_cs, 2 }, { 8_cs, 9_cs, 3 } };
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
{ {
auto timeline = original; auto timeline = original;
timeline.clear(8cs, 10cs); timeline.clear(8_cs, 10_cs);
Timeline<int> expected{ { 1cs, 2cs, 1 }, { 2cs, 5cs, 2 }, { 7cs, 8cs, 3 } }; Timeline<int> expected{ { 1_cs, 2_cs, 1 }, { 2_cs, 5_cs, 2 }, { 7_cs, 8_cs, 3 } };
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
} }
@ -189,23 +189,23 @@ void testSetter(std::function<void(const Timed<int>&, Timeline<int>&)> set) {
Timeline<int> timeline; Timeline<int> timeline;
vector<optional<int>> expectedValues(20, none); vector<optional<int>> expectedValues(20, none);
auto newElements = { auto newElements = {
Timed<int>(1cs, 2cs, 4), Timed<int>(1_cs, 2_cs, 4),
Timed<int>(3cs, 6cs, 4), Timed<int>(3_cs, 6_cs, 4),
Timed<int>(7cs, 9cs, 5), Timed<int>(7_cs, 9_cs, 5),
Timed<int>(9cs, 10cs, 6), Timed<int>(9_cs, 10_cs, 6),
Timed<int>(2cs, 3cs, 4), Timed<int>(2_cs, 3_cs, 4),
Timed<int>(0cs, 1cs, 7), Timed<int>(0_cs, 1_cs, 7),
Timed<int>(-10cs, 1cs, 8), Timed<int>(-10_cs, 1_cs, 8),
Timed<int>(-10cs, 0cs, 9), Timed<int>(-10_cs, 0_cs, 9),
Timed<int>(-10cs, -1cs, 10), Timed<int>(-10_cs, -1_cs, 10),
Timed<int>(9cs, 20cs, 11), Timed<int>(9_cs, 20_cs, 11),
Timed<int>(10cs, 20cs, 12), Timed<int>(10_cs, 20_cs, 12),
Timed<int>(11cs, 20cs, 13), Timed<int>(11_cs, 20_cs, 13),
Timed<int>(4cs, 6cs, 14), Timed<int>(4_cs, 6_cs, 14),
Timed<int>(4cs, 6cs, 15), Timed<int>(4_cs, 6_cs, 15),
Timed<int>(8cs, 10cs, 15), Timed<int>(8_cs, 10_cs, 15),
Timed<int>(6cs, 8cs, 15), Timed<int>(6_cs, 8_cs, 15),
Timed<int>(6cs, 8cs, 16) Timed<int>(6_cs, 8_cs, 16)
}; };
int newElementIndex = -1; int newElementIndex = -1;
for (const auto& newElement : newElements) { for (const auto& newElement : newElements) {
@ -214,14 +214,14 @@ void testSetter(std::function<void(const Timed<int>&, Timeline<int>&)> set) {
set(newElement, timeline); set(newElement, timeline);
// Update expected value for every index // Update expected value for every index
centiseconds elementStart = max(newElement.getStart(), 0cs); centiseconds elementStart = max(newElement.getStart(), 0_cs);
centiseconds elementEnd = newElement.getEnd(); centiseconds elementEnd = newElement.getEnd();
for (centiseconds t = elementStart; t < elementEnd; ++t) { for (centiseconds t = elementStart; t < elementEnd; ++t) {
expectedValues[t.count()] = newElement.getValue(); expectedValues[t.count()] = newElement.getValue();
} }
// Check timeline via indexer // Check timeline via indexer
for (centiseconds t = 0cs; t < 10cs; ++t) { for (centiseconds t = 0_cs; t < 10_cs; ++t) {
optional<const int&> actual = timeline[t]; optional<const int&> actual = timeline[t];
EXPECT_EQ(expectedValues[t.count()], actual ? optional<int>(*actual) : none); EXPECT_EQ(expectedValues[t.count()], actual ? optional<int>(*actual) : none);
} }
@ -230,7 +230,7 @@ void testSetter(std::function<void(const Timed<int>&, Timeline<int>&)> set) {
Timed<int> lastElement(centiseconds::min(), centiseconds::min(), std::numeric_limits<int>::min()); Timed<int> lastElement(centiseconds::min(), centiseconds::min(), std::numeric_limits<int>::min());
for (const auto& element : timeline) { for (const auto& element : timeline) {
// No element shound have zero-length // No element shound have zero-length
EXPECT_LT(0cs, element.getTimeRange().getLength()); EXPECT_LT(0_cs, element.getTimeRange().getLength());
// No two adjacent elements should have the same value; they should have been merged // No two adjacent elements should have the same value; they should have been merged
if (element.getStart() == lastElement.getEnd()) { if (element.getStart() == lastElement.getEnd()) {
@ -264,9 +264,9 @@ TEST(Timeline, set) {
} }
TEST(Timeline, indexer_get) { TEST(Timeline, indexer_get) {
Timeline<int> timeline{ { 1cs, 2cs, 1 }, { 2cs, 4cs, 2 }, { 6cs, 9cs, 3 } }; Timeline<int> timeline{ { 1_cs, 2_cs, 1 }, { 2_cs, 4_cs, 2 }, { 6_cs, 9_cs, 3 } };
vector<optional<int>> expectedValues{ none, 1, 2, 2, none, none, 3, 3, 3 }; vector<optional<int>> expectedValues{ none, 1, 2, 2, none, none, 3, 3, 3 };
for (centiseconds t = 0cs; t < 9cs; ++t) { for (centiseconds t = 0_cs; t < 9_cs; ++t) {
{ {
optional<const int&> actual = timeline[t]; optional<const int&> actual = timeline[t];
EXPECT_EQ(expectedValues[t.count()], actual ? optional<int>(*actual) : none); EXPECT_EQ(expectedValues[t.count()], actual ? optional<int>(*actual) : none);
@ -297,18 +297,18 @@ TEST(Timeline, indexer_set) {
} }
TEST(Timeline, shift) { TEST(Timeline, shift) {
Timeline<int> timeline{ { 1cs, 2cs, 1 },{ 2cs, 5cs, 2 },{ 7cs, 9cs, 3 } }; Timeline<int> timeline{ { 1_cs, 2_cs, 1 },{ 2_cs, 5_cs, 2 },{ 7_cs, 9_cs, 3 } };
Timeline<int> expected{ { 3cs, 4cs, 1 },{ 4cs, 7cs, 2 },{ 9cs, 11cs, 3 } }; Timeline<int> expected{ { 3_cs, 4_cs, 1 },{ 4_cs, 7_cs, 2 },{ 9_cs, 11_cs, 3 } };
timeline.shift(2cs); timeline.shift(2_cs);
EXPECT_EQ(expected, timeline); EXPECT_EQ(expected, timeline);
} }
TEST(Timeline, equality) { TEST(Timeline, equality) {
vector<Timeline<int>> timelines = { vector<Timeline<int>> timelines = {
Timeline<int>{}, Timeline<int>{},
Timeline<int>{ { 1cs, 2cs, 0 } }, Timeline<int>{ { 1_cs, 2_cs, 0 } },
Timeline<int>{ { 1cs, 2cs, 1 } }, Timeline<int>{ { 1_cs, 2_cs, 1 } },
Timeline<int>{ { -10cs, 0cs, 0 } } Timeline<int>{ { -10_cs, 0_cs, 0 } }
}; };
for (size_t i = 0; i < timelines.size(); ++i) { for (size_t i = 0; i < timelines.size(); ++i) {