Skip to content

Commit

Permalink
Implement BeforeOutputFormat() (#121)
Browse files Browse the repository at this point in the history
Resolves #38
  • Loading branch information
fushar committed Feb 7, 2017
1 parent 284afff commit 522fceb
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 1 deletion.
6 changes: 6 additions & 0 deletions docs/api-ref/api-ref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ Input/output formats

Defines the input format. It is mandatory.

.. sourcecode:: cpp

virtual void BeforeOutputFormat() {}

Executed right before the produced output is validated against the output format. See :ref:`io-formats_before-output-format` for more details.

.. sourcecode:: cpp

virtual void OutputFormat() {}
Expand Down
22 changes: 22 additions & 0 deletions docs/topic-guides/io-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,28 @@ For more details, consult the :ref:`API reference for I/O formats <api-ref_io-fo

----

.. _io-formats_before-output-format:

BeforeOutputFormat()
--------------------

The special ``BeforeOutputFormat()`` method, if specified, will be executed right before the produced output is validated against the output format. It is useful when the output format segments depend on the input variables. For example, suppose that the input is a list of commands, each of which is either a query or an update. The output should contain as many lines as the number of update commands present in the input.

You can declare a helper variable, e.g. ``update_count``, and have ``LINES(answers) % SIZE(update_count)`` as the output format. Then, compute the value of ``update_count`` in the ``BeforeOutputFormat()`` method. For example:

.. sourcecode:: cpp

int update_count;
vector<int> answers;

void BeforeOutputFormat() {
// count the number of update queries and assign it to update_count
}

void OutputFormat() {
LINES(answers) % SIZE(update_count);
}

Notes
-----

Expand Down
1 change: 1 addition & 0 deletions include/tcframe/io_manipulator/IOManipulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class IOManipulator {

virtual void parseOutput(istream* in) {
if (!ioFormat_.outputFormat().empty()) {
ioFormat_.beforeOutputFormat()();
parse(ioFormat_.outputFormat(), in);
}
}
Expand Down
4 changes: 4 additions & 0 deletions include/tcframe/spec/core/BaseProblemSpec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class BaseProblemSpec
IOFormat buildIOFormat() {
IOFormatBuilder::prepareForInputFormat();
InputFormat();
IOFormatBuilder::setBeforeOutputFormat([this] {
BeforeOutputFormat();
});
IOFormatBuilder::prepareForOutputFormat();
OutputFormat();
return IOFormatBuilder::build();
Expand Down Expand Up @@ -91,6 +94,7 @@ class BaseProblemSpec

protected:
virtual void InputFormat() = 0;
virtual void BeforeOutputFormat() {}
virtual void OutputFormat() {}
virtual void StyleConfig() {}
virtual void GradingConfig() {}
Expand Down
11 changes: 11 additions & 0 deletions include/tcframe/spec/io/IOFormat.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <functional>
#include <stdexcept>
#include <utility>
#include <vector>
Expand All @@ -11,6 +12,7 @@
#include "RawLineIOSegment.hpp"
#include "RawLinesIOSegment.hpp"

using std::function;
using std::move;
using std::runtime_error;
using std::vector;
Expand All @@ -22,13 +24,18 @@ struct IOFormat {

private:
vector<IOSegment*> inputFormat_;
function<void()> beforeOutputFormat_;
vector<IOSegment*> outputFormat_;

public:
const vector<IOSegment*>& inputFormat() const {
return inputFormat_;
}

const function<void()>& beforeOutputFormat() const {
return beforeOutputFormat_;
}

const vector<IOSegment*>& outputFormat() const {
return outputFormat_;
}
Expand Down Expand Up @@ -68,6 +75,10 @@ class IOFormatBuilder {
currentFormat_ = &subject_.inputFormat_;
}

void setBeforeOutputFormat(function<void()> beforeOutputFormat) {
subject_.beforeOutputFormat_ = beforeOutputFormat;
}

void prepareForOutputFormat() {
addLastSegment();
currentFormat_ = &subject_.outputFormat_;
Expand Down
7 changes: 7 additions & 0 deletions test/ete/resources/normal-lifecycle/solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <cstdio>

int main() {
printf("even\n");
printf("odd\n");
printf("even\n");
}
64 changes: 64 additions & 0 deletions test/ete/resources/normal-lifecycle/spec.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <bits/stdc++.h>
#include <tcframe/spec.hpp>

using namespace std;
using namespace tcframe;

class ProblemSpec : public BaseProblemSpec {
protected:
int N;
vector<int> A;

int positive_count;
vector<string> answers;

void InputFormat() {
LINE(N);
LINE(A % SIZE(N));
}

void BeforeOutputFormat() {
positive_count = count_if(A.begin(), A.end(), [](int a) {return a > 0;});
}

void OutputFormat() {
LINES(answers) % SIZE(positive_count);
}

void GradingConfig() {
TimeLimit(2);
MemoryLimit(64);
}

void Constraints() {
CONS(1 <= N && N <= 10);
}
};

class TestSpec : public BaseTestSpec<ProblemSpec> {
protected:
void BeforeTestCase() {
A.clear();
}

void AfterTestCase() {
N++;
A.push_back(-100);
}

void SampleTestCase1() {
Input({
"5",
"4 -1 3 2 -5",
});
Output({
"even",
"odd",
"even"
});
}

void TestCases() {
CASE(N = 6, A = {-1, 2, 3, -4, -5, 6});
}
};
29 changes: 29 additions & 0 deletions test/ete/tcframe/GenerationEteTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,35 @@ TEST_F(GenerationEteTests, Normal_CustomScorer) {
));
}

TEST_F(GenerationEteTests, Normal_Lifecycle) {
ASSERT_THAT(execStatus("cd test-ete/normal-lifecycle && ../scripts/generate.sh"), Eq(0));

EXPECT_THAT(ls("test-ete/normal-lifecycle/tc"), UnorderedElementsAre(
"normal-lifecycle_sample_1.in",
"normal-lifecycle_sample_1.out",
"normal-lifecycle_1.in",
"normal-lifecycle_1.out"
));

EXPECT_THAT(readFile("test-ete/normal-lifecycle/tc/normal-lifecycle_sample_1.in"), Eq(
"5\n"
"4 -1 3 2 -5\n"));

EXPECT_THAT(readFile("test-ete/normal-lifecycle/tc/normal-lifecycle_sample_1.out"), Eq(
"even\n"
"odd\n"
"even\n"));

EXPECT_THAT(readFile("test-ete/normal-lifecycle/tc/normal-lifecycle_1.in"), Eq(
"7\n"
"-1 2 3 -4 -5 6 -100\n"));

EXPECT_THAT(readFile("test-ete/normal-lifecycle/tc/normal-lifecycle_1.out"), Eq(
"even\n"
"odd\n"
"even\n"));
}

TEST_F(GenerationEteTests, Subtasks) {
ASSERT_THAT(execStatus("cd test-ete/subtasks && ../scripts/generate.sh"), Eq(0));

Expand Down
22 changes: 21 additions & 1 deletion test/unit/tcframe/io_manipulator/IOManipulatorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ namespace tcframe {
class IOManipulatorTests : public Test {
protected:
int A;
int N;
string S;
vector<int> V;
vector<string> W;
vector<vector<int>> M;

IOManipulator* manipulatorEmpty;
IOManipulator* manipulatorWithOutputFormat;
IOManipulator* manipulatorWithScalarLast;
IOManipulator* manipulatorWithVectorLast;
IOManipulator* manipulatorWithMatrixLast;
IOManipulator* manipulatorEmpty;

void SetUp() {
{
Expand All @@ -34,6 +36,17 @@ class IOManipulatorTests : public Test {

manipulatorEmpty = new IOManipulator(ioFormat);
}
{
IOFormatBuilder ioFormatBuilder;
ioFormatBuilder.prepareForOutputFormat();
ioFormatBuilder.setBeforeOutputFormat([=] {N = 3;});
ioFormatBuilder.newLinesIOSegment()
.addVectorVariable(Vector::create(V, "V"))
.setSize([=] {return N;});
IOFormat ioFormat = ioFormatBuilder.build();

manipulatorWithOutputFormat = new IOManipulator(ioFormat);
}
{
IOFormatBuilder ioFormatBuilder;
ioFormatBuilder.prepareForInputFormat();
Expand Down Expand Up @@ -128,6 +141,13 @@ TEST_F(IOManipulatorTests, Parsing_Failed_MissingEof_WithMatrixLast) {
}
}

TEST_F(IOManipulatorTests, Parsing_Output) {
istringstream in("1\n2\n3\n");
N = 0;
manipulatorWithOutputFormat->parseOutput(&in);
EXPECT_THAT(V, Eq((vector<int>{1, 2, 3})));
}

TEST_F(IOManipulatorTests, Printing_Successful) {
A = 123;
S = "hello, world!";
Expand Down

0 comments on commit 522fceb

Please sign in to comment.