Bug 1255632 - Make Maybe::map and Maybe::apply support lambdas. r=waldo,njn

This commit is contained in:
Seth Fowler 2016-06-21 20:39:46 -07:00
parent 172d673bcc
commit 358b410aaa
4 changed files with 77 additions and 148 deletions

View File

@ -405,24 +405,6 @@ ClippedImage::Draw(gfxContext* aContext,
aSamplingFilter, aSVGContext, aFlags);
}
static SVGImageContext
UnclipViewport(const SVGImageContext& aOldContext,
const pair<nsIntSize, nsIntSize>& aInnerAndClipSize)
{
nsIntSize innerSize(aInnerAndClipSize.first);
nsIntSize clipSize(aInnerAndClipSize.second);
// Map the viewport to the inner image. (Note that we don't take the aSize
// parameter of Draw into account, just the clipping region.)
CSSIntSize vSize(aOldContext.GetViewportSize());
vSize.width = ceil(vSize.width * double(innerSize.width) / clipSize.width);
vSize.height =
ceil(vSize.height * double(innerSize.height) / clipSize.height);
return SVGImageContext(vSize,
aOldContext.GetPreserveAspectRatio());
}
DrawResult
ClippedImage::DrawSingleTile(gfxContext* aContext,
const nsIntSize& aSize,
@ -468,10 +450,24 @@ ClippedImage::DrawSingleTile(gfxContext* aContext,
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
aContext->Multiply(gfxMatrix::Translation(-clip.x, -clip.y));
auto unclipViewport = [&](const SVGImageContext& aOldContext) {
// Map the viewport to the inner image. Note that we don't take the aSize
// parameter of imgIContainer::Draw into account, just the clipping region.
// The size in pixels at which the output will ultimately be drawn is
// irrelevant here since the purpose of the SVG viewport size is to
// determine what *region* of the SVG document will be drawn.
CSSIntSize vSize(aOldContext.GetViewportSize());
vSize.width = ceil(vSize.width * double(innerSize.width) / mClip.width);
vSize.height =
ceil(vSize.height * double(innerSize.height) / mClip.height);
return SVGImageContext(vSize,
aOldContext.GetPreserveAspectRatio());
};
return InnerImage()->Draw(aContext, size, region,
aWhichFrame, aSamplingFilter,
aSVGContext.map(UnclipViewport,
make_pair(innerSize, mClip.Size())),
aSVGContext.map(unclipViewport),
aFlags);
}

View File

@ -256,18 +256,6 @@ OrientedImage::OrientationMatrix(const nsIntSize& aSize,
return builder.Build();
}
static SVGImageContext
OrientViewport(const SVGImageContext& aOldContext,
const Orientation& aOrientation)
{
CSSIntSize viewportSize(aOldContext.GetViewportSize());
if (aOrientation.SwapsWidthAndHeight()) {
swap(viewportSize.width, viewportSize.height);
}
return SVGImageContext(viewportSize,
aOldContext.GetPreserveAspectRatio());
}
NS_IMETHODIMP_(DrawResult)
OrientedImage::Draw(gfxContext* aContext,
const nsIntSize& aSize,
@ -303,9 +291,17 @@ OrientedImage::Draw(gfxContext* aContext,
ImageRegion region(aRegion);
region.TransformBoundsBy(inverseMatrix);
auto orientViewport = [&](const SVGImageContext& aOldContext) {
CSSIntSize viewportSize(aOldContext.GetViewportSize());
if (mOrientation.SwapsWidthAndHeight()) {
swap(viewportSize.width, viewportSize.height);
}
return SVGImageContext(viewportSize,
aOldContext.GetPreserveAspectRatio());
};
return InnerImage()->Draw(aContext, size, region, aWhichFrame, aSamplingFilter,
aSVGContext.map(OrientViewport, mOrientation),
aFlags);
aSVGContext.map(orientViewport), aFlags);
}
nsIntSize

View File

@ -324,46 +324,50 @@ public:
/* If |isSome()|, runs the provided function or functor on the contents of
* this Maybe. */
template<typename F, typename... Args>
void apply(F&& aFunc, Args&&... aArgs)
template<typename Func>
Maybe& apply(Func aFunc)
{
if (isSome()) {
aFunc(ref(), Forward<Args>(aArgs)...);
aFunc(ref());
}
return *this;
}
template<typename F, typename... Args>
void apply(F&& aFunc, Args&&... aArgs) const
template<typename Func>
const Maybe& apply(Func aFunc) const
{
if (isSome()) {
aFunc(ref(), Forward<Args>(aArgs)...);
aFunc(ref());
}
return *this;
}
/*
* If |isSome()|, runs the provided function and returns the result wrapped
* in a Maybe. If |isNothing()|, returns an empty Maybe value.
*/
template<typename R, typename... FArgs, typename... Args>
Maybe<R> map(R (*aFunc)(T&, FArgs...), Args&&... aArgs)
template<typename Func>
auto map(Func aFunc) -> Maybe<decltype(aFunc(ref()))>
{
using ReturnType = decltype(aFunc(ref()));
if (isSome()) {
Maybe<R> val;
val.emplace(aFunc(ref(), Forward<Args>(aArgs)...));
Maybe<ReturnType> val;
val.emplace(aFunc(ref()));
return val;
}
return Maybe<R>();
return Maybe<ReturnType>();
}
template<typename R, typename... FArgs, typename... Args>
Maybe<R> map(R (*aFunc)(const T&, FArgs...), Args&&... aArgs) const
template<typename Func>
auto map(Func aFunc) const -> Maybe<decltype(aFunc(ref()))>
{
using ReturnType = decltype(aFunc(ref()));
if (isSome()) {
Maybe<R> val;
val.emplace(aFunc(ref(), Forward<Args>(aArgs)...));
Maybe<ReturnType> val;
val.emplace(aFunc(ref()));
return val;
}
return Maybe<R>();
return Maybe<ReturnType>();
}
/* If |isSome()|, empties this Maybe and destroys its contents. */

View File

@ -526,48 +526,22 @@ IncrementTag(BasicValue& aValue)
aValue.SetTag(aValue.GetTag() + 1);
}
static void
IncrementTagBy(BasicValue& aValue, int aAmount)
{
gFunctionWasApplied = true;
aValue.SetTag(aValue.GetTag() + aAmount);
}
static void
AccessValue(const BasicValue&)
{
gFunctionWasApplied = true;
}
static void
AccessValueWithArg(const BasicValue&, int)
{
gFunctionWasApplied = true;
}
struct IncrementTagFunctor
{
IncrementTagFunctor() : mBy(1), mArgMoved(false) { }
IncrementTagFunctor() : mBy(1) { }
void operator()(BasicValue& aValue)
{
aValue.SetTag(aValue.GetTag() + mBy.GetTag());
}
void operator()(BasicValue& aValue, const BasicValue& aArg)
{
mArgMoved = false;
aValue.SetTag(aValue.GetTag() + aArg.GetTag());
}
void operator()(BasicValue& aValue, BasicValue&& aArg)
{
mArgMoved = true;
aValue.SetTag(aValue.GetTag() + aArg.GetTag());
}
BasicValue mBy;
bool mArgMoved;
};
static bool
@ -578,8 +552,6 @@ TestApply()
Maybe<BasicValue> mayValue;
mayValue.apply(&IncrementTag);
mayValue.apply(&AccessValue);
mayValue.apply(&IncrementTagBy, 1);
mayValue.apply(&AccessValueWithArg, 1);
MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
// Check that apply handles the 'Some' case.
@ -590,22 +562,12 @@ TestApply()
gFunctionWasApplied = false;
mayValue.apply(&AccessValue);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
gFunctionWasApplied = false;
mayValue.apply(&IncrementTagBy, 2);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 4);
gFunctionWasApplied = false;
mayValue.apply(&AccessValueWithArg, 1);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
// Check that apply works with a const reference.
const Maybe<BasicValue>& mayValueCRef = mayValue;
gFunctionWasApplied = false;
mayValueCRef.apply(&AccessValue);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
gFunctionWasApplied = false;
mayValueCRef.apply(&AccessValueWithArg, 1);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
// Check that apply works with functors.
IncrementTagFunctor tagIncrementer;
@ -614,15 +576,17 @@ TestApply()
mayValue.apply(tagIncrementer);
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
mayValue.apply(tagIncrementer, BasicValue(2));
// Check that apply works with lambda expressions.
int32_t two = 2;
gFunctionWasApplied = false;
mayValue = Some(BasicValue(2));
mayValue.apply([&](BasicValue& aVal) { aVal.SetTag(aVal.GetTag() * two); });
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 4);
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(tagIncrementer.mArgMoved == true);
BasicValue incrementBy(3);
mayValue.apply(tagIncrementer, incrementBy);
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 7);
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(tagIncrementer.mArgMoved == false);
mayValue.apply([=](BasicValue& aVal) { aVal.SetTag(aVal.GetTag() * two); });
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 8);
mayValueCRef.apply([&](const BasicValue& aVal) { gFunctionWasApplied = true; });
MOZ_RELEASE_ASSERT(gFunctionWasApplied == true);
return true;
}
@ -641,43 +605,16 @@ TimesTwoAndResetOriginal(BasicValue& aValue)
return tag * 2;
}
static int
TimesNum(const BasicValue& aValue, int aNum)
{
return aValue.GetTag() * aNum;
}
static int
TimesNumAndResetOriginal(BasicValue& aValue, int aNum)
{
int tag = aValue.GetTag();
aValue.SetTag(1);
return tag * aNum;
}
struct MultiplyTagFunctor
{
MultiplyTagFunctor() : mBy(2), mArgMoved(false) { }
MultiplyTagFunctor() : mBy(2) { }
int operator()(BasicValue& aValue)
{
return aValue.GetTag() * mBy.GetTag();
}
int operator()(BasicValue& aValue, const BasicValue& aArg)
{
mArgMoved = false;
return aValue.GetTag() * aArg.GetTag();
}
int operator()(BasicValue& aValue, BasicValue&& aArg)
{
mArgMoved = true;
return aValue.GetTag() * aArg.GetTag();
}
BasicValue mBy;
bool mArgMoved;
};
static bool
@ -690,11 +627,6 @@ TestMap()
DECLTYPE(mayValue.map(&TimesTwo))>::value,
"map(TimesTwo) should return a Maybe<int>");
MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwoAndResetOriginal) == Nothing());
MOZ_RELEASE_ASSERT(mayValue.map(&TimesNum, 3) == Nothing());
static_assert(IsSame<Maybe<int>,
DECLTYPE(mayValue.map(&TimesNum, 3))>::value,
"map(TimesNum, 3) should return a Maybe<int>");
MOZ_RELEASE_ASSERT(mayValue.map(&TimesNumAndResetOriginal, 3) == Nothing());
// Check that map handles the 'Some' case.
mayValue = Some(BasicValue(2));
@ -702,9 +634,6 @@ TestMap()
MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwoAndResetOriginal) == Some(4));
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
mayValue = Some(BasicValue(2));
MOZ_RELEASE_ASSERT(mayValue.map(&TimesNum, 3) == Some(6));
MOZ_RELEASE_ASSERT(mayValue.map(&TimesNumAndResetOriginal, 3) == Some(6));
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
// Check that map works with a const reference.
mayValue->SetTag(2);
@ -713,27 +642,31 @@ TestMap()
static_assert(IsSame<Maybe<int>,
DECLTYPE(mayValueCRef.map(&TimesTwo))>::value,
"map(TimesTwo) should return a Maybe<int>");
MOZ_RELEASE_ASSERT(mayValueCRef.map(&TimesNum, 3) == Some(6));
static_assert(IsSame<Maybe<int>,
DECLTYPE(mayValueCRef.map(&TimesNum, 3))>::value,
"map(TimesNum, 3) should return a Maybe<int>");
// Check that map works with functors.
// XXX(seth): Support for functors will be added in bug 1054115; it had to be
// ripped out temporarily because of incompatibilities with GCC 4.4.
/*
MultiplyTagFunctor tagMultiplier;
MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier) == Some(4));
MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier, BasicValue(3)) == Some(6));
MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(tagMultiplier.mArgMoved == true);
BasicValue multiplyBy(3);
MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier, multiplyBy) == Some(6));
MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(tagMultiplier.mArgMoved == false);
*/
// Check that map works with lambda expressions.
int two = 2;
mayValue = Some(BasicValue(2));
Maybe<int> mappedValue =
mayValue.map([&](const BasicValue& aVal) {
return aVal.GetTag() * two;
});
MOZ_RELEASE_ASSERT(mappedValue == Some(4));
mappedValue =
mayValue.map([=](const BasicValue& aVal) {
return aVal.GetTag() * two;
});
MOZ_RELEASE_ASSERT(mappedValue == Some(4));
mappedValue =
mayValueCRef.map([&](const BasicValue& aVal) {
return aVal.GetTag() * two;
});
MOZ_RELEASE_ASSERT(mappedValue == Some(4));
return true;
}