<commit_before>#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/GlobalAlias.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Constants.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "IMPCacher.h"

void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
    *version) {

  BasicBlock *beforeLookupBB = lookup->getParent();
  BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner);
  BasicBlock::iterator iter = lookup;
  iter++;
  BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);

  beforeLookupBB->getTerminator()->removeFromParent();

  IRBuilder<> B = IRBuilder<>(beforeLookupBB);
  // Load the slot and check that neither it nor the version is 0.
  Value *slotValue = B.CreateLoad(slot);
  Value *versionValue = B.CreateLoad(version);
  Value *receiver = lookup->getOperand(1);

  Value *isCacheEmpty =
        B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy));
  isCacheEmpty =
    B.CreateICmpEQ(isCacheEmpty, Constant::getNullValue(IntTy));
  Value *receiverNotNil =
     B.CreateICmpNE(receiver, Constant::getNullValue(receiver->getType()));
  isCacheEmpty = B.CreateAnd(isCacheEmpty, receiverNotNil);

  BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check",
      lookupBB->getParent());

  B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB);

  // Check the cache node is current
  B.SetInsertPoint(cacheLookupBB);
  Value *slotVersion = B.CreateStructGEP(slotValue, 3);
  // Note: Volatile load because the slot version might have changed in
  // another thread.
  slotVersion = B.CreateLoad(slotVersion, true, "slot_version");
  Value *slotCachedFor = B.CreateStructGEP(slotValue, 1);
  slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner");
  Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue);
  Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls);
  Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect);
  // If this slot is still valid, skip the lookup.
  B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB);

  // Replace the looked up slot with the loaded one
  B.SetInsertPoint(afterLookupBB, afterLookupBB->begin());
  // Not volatile, so a redundant load elimination pass can do some phi
  // magic with this later.
  lookup->replaceAllUsesWith(B.CreateLoad(slot));

  // Perform the real lookup and cache the result
  lookupBB->getTerminator()->removeFromParent();
  B.SetInsertPoint(lookupBB);
  // Store it even if the version is 0, because we always check that the
  // version is not 0 at the start and an occasional redundant store is
  // probably better than a branch every time.
  B.CreateStore(lookup, slot);
  B.CreateStore(B.CreateLoad(B.CreateStructGEP(lookup, 3)), version);
  cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  B.CreateStore(cls, B.CreateStructGEP(lookup, 1));
  B.CreateBr(afterLookupBB);
}

<commit_msg>Fixed IMP cacher to not cache the slot if the lookup function changes the receiver (this could result in a method being called on the wrong receiver, which would just be confusing).<commit_after>#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/GlobalAlias.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Constants.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "IMPCacher.h"

void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
    *version) {

  BasicBlock *beforeLookupBB = lookup->getParent();
  BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner);
  BasicBlock::iterator iter = lookup;
  iter++;
  BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);

  beforeLookupBB->getTerminator()->removeFromParent();

  IRBuilder<> B = IRBuilder<>(beforeLookupBB);
  // Load the slot and check that neither it nor the version is 0.
  Value *slotValue = B.CreateLoad(slot);
  Value *versionValue = B.CreateLoad(version);
  Value *receiverPtr = lookup->getOperand(1);
  Value *receiver = B.CreateLoad(receiverPtr);

  Value *isCacheEmpty =
        B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy));
  isCacheEmpty =
    B.CreateICmpEQ(isCacheEmpty, Constant::getNullValue(IntTy));
  Value *receiverNotNil =
     B.CreateICmpNE(receiver, Constant::getNullValue(receiver->getType()));
  isCacheEmpty = B.CreateAnd(isCacheEmpty, receiverNotNil);

  BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check",
      lookupBB->getParent());

  B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB);

  // Check the cache node is current
  B.SetInsertPoint(cacheLookupBB);
  Value *slotVersion = B.CreateStructGEP(slotValue, 3);
  // Note: Volatile load because the slot version might have changed in
  // another thread.
  slotVersion = B.CreateLoad(slotVersion, true, "slot_version");
  Value *slotCachedFor = B.CreateStructGEP(slotValue, 1);
  slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner");
  Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue);
  Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls);
  Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect);
  // If this slot is still valid, skip the lookup.
  B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB);

  // Replace the looked up slot with the loaded one
  B.SetInsertPoint(afterLookupBB, afterLookupBB->begin());
  // Not volatile, so a redundant load elimination pass can do some phi
  // magic with this later.
  lookup->replaceAllUsesWith(B.CreateLoad(slot));

  // Perform the real lookup and cache the result
  lookupBB->getTerminator()->removeFromParent();
  B.SetInsertPoint(lookupBB);
  Value * newReceiver = B.CreateLoad(receiverPtr);
  BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store",
      lookupBB->getParent());

  // Don't store the cached lookup if we are doing forwarding tricks.
  B.CreateCondBr(B.CreateICmpEQ(receiver, newReceiver), storeCacheBB,
      afterLookupBB);
  B.SetInsertPoint(storeCacheBB);

  // Store it even if the version is 0, because we always check that the
  // version is not 0 at the start and an occasional redundant store is
  // probably better than a branch every time.
  B.CreateStore(lookup, slot);
  B.CreateStore(B.CreateLoad(B.CreateStructGEP(lookup, 3)), version);
  cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  B.CreateStore(cls, B.CreateStructGEP(lookup, 1));
  B.CreateBr(afterLookupBB);
}

<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <stdexcept>

#include "SemanticAnalyser.hpp"

using namespace ::testing;

struct SemanticAnalyserTest : public Test
{
    SemanticAnalyser analyser;

    static constexpr Token createTokenWithZeroValue(TokenType type)
    {
        return {type, 0};
    }

    static constexpr Instruction
    createInstructionWithZeroValue(InstructionType type)
    {
        return {type, 0};
    }
};

TEST_F(SemanticAnalyserTest, ShouldAcceptEmptyTokens)
{
    Tokens tokens{};
    Instructions instructions;
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstructionSet)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld)};
    ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                  createTokenWithZeroValue(TokenType::A)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::LdA)};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::ZeroWithBracketsA)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::OutA)};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::Ld)};
    ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldRejectInvalidLdInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                  createTokenWithZeroValue(TokenType::A),
                  createTokenWithZeroValue(TokenType::Out)};
    ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstructionFollowedByLd)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::ZeroWithBracketsA),
                  createTokenWithZeroValue(TokenType::Ld),
                  createTokenWithZeroValue(TokenType::A)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::OutA),
        createInstructionWithZeroValue(InstructionType::LdA)};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstructionWithValue)
{
    constexpr auto number = 42u;
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                  {TokenType::A, number}};
    Instructions instructions{{InstructionType::LdA, number}};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstructionFollowedByLdWithValue)
{
    constexpr auto number = 42u;
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::ZeroWithBracketsA),
                  createTokenWithZeroValue(TokenType::Ld),
                  {TokenType::A, number}};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::OutA),
        {InstructionType::LdA, number}};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, DISABLED_ShouldAccepRlcaInsruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Rlca)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::Rlca)};

    ASSERT_EQ(instructions, analyser.analyse(tokens));
}
<commit_msg>Move checking size of instruction to instruction test<commit_after>#include "gtest/gtest.h"

#include <stdexcept>

#include "SemanticAnalyser.hpp"

using namespace ::testing;

struct SemanticAnalyserTest : public Test
{
    SemanticAnalyser analyser;

    static constexpr Token createTokenWithZeroValue(TokenType type)
    {
        return {type, 0};
    }

    static constexpr Instruction
    createInstructionWithZeroValue(InstructionType type)
    {
        return {type, 0};
    }
};

TEST_F(SemanticAnalyserTest, ShouldAcceptEmptyTokens)
{
    Tokens tokens{};
    Instructions instructions;
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstructionSet)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld)};
    ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                  createTokenWithZeroValue(TokenType::A)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::LdA)};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::ZeroWithBracketsA)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::OutA)};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::Ld)};
    ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldRejectInvalidLdInstruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                  createTokenWithZeroValue(TokenType::A),
                  createTokenWithZeroValue(TokenType::Out)};
    ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstructionFollowedByLd)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::ZeroWithBracketsA),
                  createTokenWithZeroValue(TokenType::Ld),
                  createTokenWithZeroValue(TokenType::A)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::OutA),
        createInstructionWithZeroValue(InstructionType::LdA)};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstructionWithValue)
{
    constexpr auto number = 42u;
    Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                  {TokenType::A, number}};
    Instructions instructions{{InstructionType::LdA, number}};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstructionFollowedByLdWithValue)
{
    constexpr auto number = 42u;
    Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                  createTokenWithZeroValue(TokenType::ZeroWithBracketsA),
                  createTokenWithZeroValue(TokenType::Ld),
                  {TokenType::A, number}};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::OutA),
        {InstructionType::LdA, number}};
    ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAccepRlcaInsruction)
{
    Tokens tokens{createTokenWithZeroValue(TokenType::Rlca)};
    Instructions instructions{
        createInstructionWithZeroValue(InstructionType::Rlca)};

    ASSERT_EQ(instructions, analyser.analyse(tokens));
}
<|endoftext|>


<commit_before>/**
 * @copyright
 * ========================================================================
 *	Copyright 2006-2007 FLWOR Foundation
 * ========================================================================
 *
 * @author Sorin Nasoi (sorin.nasoi@ipdevel.ro)
 * @file functions/StringsImpl.cpp
 *
 */

#include <iostream>

#include "runtime/strings/StringsImpl.h"
#include "util/tracer.h"
#include "types/casting.h"
#include "errors/Error.h"
#include "util/zorba.h"
#include "util/utf8/utf8.h"

using namespace std;
namespace xqp {
/**
 *______________________________________________________________________
 *
 *	7.2.1 fn:codepoints-to-string
 *
 *	fn:codepoints-to-string($arg as xs:integer*) as xs:string
 *
 *	Summary:Creates an xs:string from a sequence of code points.
 *Returns the zero-length string if $arg is the empty sequence.
 *If any of the code points in $arg is not a legal XML character,
 *an error is raised [err:FOCH0001] ("Code point not valid.").
 *_______________________________________________________________________*/
/* begin class CodepointsToStringIterator */
Item_t CodepointsToStringIterator::nextImpl(PlanState& planState){
	Item_t item;
	Item_t resItem;
	xqp_string resStr;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	while(true){
		item = consumeNext ( theChild, planState );
		if ( item != NULL ){
			item = item->getAtomizationValue();
			resStr += (uint32_t)item->getIntegerValue();
		}
		else{
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createString(resStr);
			STACK_PUSH2( resItem, state );
			break;
		}
	}
	STACK_END2();
}
/* end class CodepointsToStringIterator */

/**
 *______________________________________________________________________
 *
 *	7.2.2 fn:string-to-codepoints
 *
 *	fn:string-to-codepoints($arg as xs:string?) as xs:integer*
 *
 *	Summary: Returns the sequence of code points that constitute an
 *xs:string.
 *If $arg is a zero-length string or the empty sequence,
 *the empty sequence is returned.
 *_______________________________________________________________________*/
/* begin class StringToCodepointsIterator */
Item_t StringToCodepointsIterator::nextImpl(PlanState& planState){
/*
	Item_t item;
	Item_t resItem;
	xqp_string inputStr;
	std::vector<int> resVector;
	std::vector<int>::iterator iter;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	item = consumeNext ( theChild, planState );
	if ( item != NULL ){
		inputStr = item->getStringValue();
		resVector = inputStr.getCodepoints();
		for(iter = resVector.begin(); iter != resVector.end(); iter++){
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createInteger(*iter);
			STACK_PUSH2( resItem, state );
		}
	}
	STACK_END2();
*/
	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);
	STACK_END2();
}
/* end class StringToCodepointsIterator */

/**
 *______________________________________________________________________
 *	7.3.2 fn:compare
 * fn:compare($comparand1 as xs:string?,
 * 									$comparand2 as xs:string?) as xs:integer
 *
 * fn:compare( 	$comparand1	as xs:string?,
 * 										$comparand2	as xs:string?,
 * 										$collation	as xs:string) as xs:integer?
 *
 * Summary: Returns -1, 0, or 1, depending on whether the value of
 * the $comparand1 is respectively less than, equal to, or greater
 * than the value of $comparand2, according to the rules of
 * the collation that is used.
 *
 * If either argument is the empty sequence, the result is the empty sequence.
 *_______________________________________________________________________*/

/* begin class CompareStrIterator */
Item_t
CompareStrIterator::nextImpl(PlanState& planState) {
	Item_t n0;
	Item_t n1;
	Item_t n2;
	Item_t res;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	n0 = consumeNext ( theChildren[0], planState );
	if ( n0 != NULL )	{
		n1 = consumeNext ( theChildren[1], planState );
		if ( n1 != NULL )	{
			n0 = n0->getAtomizationValue();
			n1 = n1->getAtomizationValue();
			n2 = consumeNext ( theChildren[2], planState );
			if(theChildren.size() == 3)	{
				if ( n2 != NULL )	{
					//TODO solve track issue no.26
					res = zorba::getZorbaForCurrentThread()->getItemFactory()->createInteger(
									n0->getStringValue().compare(n1->getStringValue(), n2->getStringValue().c_str()));
				}
			}
			else{
				res = zorba::getZorbaForCurrentThread()->getItemFactory()->createInteger(
								n0->getStringValue().compare(n1->getStringValue()));
			}
			STACK_PUSH2( res, state );
		}
	}

	STACK_END2();
}
/* end class CompareStrIterator */

/**
 *______________________________________________________________________
 *
 *	7.3.3 fn:codepoint-equal
 *
 *	fn:codepoint-equal( 	$comparand1 	 as xs:string?,
 *  											$comparand2 	 as xs:string?) as xs:boolean?
 *
 *	Summary: Returns true or false depending on whether the value
 * of $comparand1 is equal to the value of $comparand2, according to
 * the Unicode code point collation
 * (http://www.w3.org/2005/xpath-functions/collation/codepoint).
 *
 * If either argument is the empty sequence, the result is the empty sequence.
 *
 * Note: This function allows xs:anyURI values to be compared
 * without having to specify the Unicode code point collation.
 *_______________________________________________________________________*/
/* begin class CodepointEqualIterator */
Item_t CodepointEqualIterator::nextImpl(PlanState& planState){
		Item_t item0;
		Item_t item1;
		Item_t res;

		PlanIterator::PlanIteratorState* state;
		STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

		item0 = consumeNext ( theChild0, planState );
		if ( item0 != NULL )	{
			item1 = consumeNext ( theChild1, planState );
			if ( item1 != NULL )	{
				item0 = item0->getAtomizationValue();
				item1 = item1->getAtomizationValue();
				res = zorba::getZorbaForCurrentThread()->getItemFactory()->createBoolean(
									item0->getStringValue() == item1->getStringValue());
				STACK_PUSH2( res, state );
			}
		}
		STACK_END2();
}
/* end class CodepointEqualIterator */
/**
 *______________________________________________________________________
 *
 *	7.4.1 fn:concat
 *
 * fn:concat( 	$arg1 	 as xs:anyAtomicType?,
 * 									$arg2 	 as xs:anyAtomicType?,
 * 									...																					) as xs:string
 *
 * Summary:
 * Accepts two or more xs:anyAtomicType arguments and casts them to xs:string.
 * Returns the xs:string that is the concatenation of the values of its
 * arguments after conversion.
 * If any of the arguments is the empty sequence, the argument is treated
 * as the zero-length string.
 *
 * The fn:concat function is specified to allow an two or more arguments
 * that are concatenated together.
 *
 * Note:
 * Unicode normalization is not automatically applied to the result
 * of fn:concat. If a normalized result is required, fn:normalize-unicode
 * can be applied to the xs:string returned by fn:concat.
 *_______________________________________________________________________*/
/* begin class ConcatStrIterator */
Item_t ConcatStrIterator::nextImpl(PlanState& planState) {
	//TODO this function is not implemented for a variable number of arguments
	Item_t item0;
	Item_t item1;
	Item_t res;
	xqp_string s0,s1;
	int argsNo = theChildren.size();
	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	if(argsNo >= 1){
		item0 = consumeNext ( theChildren[0], planState );
		if(argsNo ==1){
			STACK_PUSH2( item0, state );
		}
		else{
			item1 = consumeNext ( theChildren[1], planState );
			s0 = item0->getStringValue();
			s1 = item1->getStringValue();
			//TODO ask about this error
			//Details: fn:concat("0","1")
			//theChildren[0] atomic value is 1 and
			//theChildren[1] atomic value is 0
			res = zorba::getZorbaForCurrentThread()->getItemFactory()->createString(
							item0->getStringValue() += item1->getStringValue());
			STACK_PUSH2( res, state );
		}
	}
	STACK_END2();
}
/* end class ConcatStrIterator */

/**
 *______________________________________________________________________
 *
 *	7.4.2 fn:string-join
 *
 * fn:string-join($arg1 as xs:string*,
 * 										$arg2 as xs:string) as xs:string
 *
 * Summary: Returns a xs:string created by concatenating the members
 * of the $arg1 sequence using $arg2 as a separator.
 *
 * If the value of $arg2 is the zero-length string,
 * then the members of $arg1 are concatenated without a separator.
 *
 * If the value of $arg1 is the empty sequence,
 * the zero-length string is returned.
 *_______________________________________________________________________*/
/* begin class StringJoinIterator */
Item_t StringJoinIterator::nextImpl(PlanState& planState) {
	Item_t item;
	Item_t resItem;
	xqp_string resStr;
	xqp_string separator;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

//TODO this is not correct:
//Step 1: find the separator based on the type (item not sequence)
//step 2: concatenate the items whithin the sequence using separator as "glue"
	while(true){
		item = consumeNext ( theChild0, planState );
		if ( item != NULL ){
			item = item->getAtomizationValue();
			resStr += item->getStringValue();
		}
		else{
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createString(resStr);
			STACK_PUSH2( resItem, state );
			break;
		}
	}
	STACK_END2();
}
/* end class StringJoinIterator */
} /* namespace xqp */
<commit_msg>Changes to string iterators<commit_after>/**
 * @copyright
 * ========================================================================
 *	Copyright 2006-2007 FLWOR Foundation
 * ========================================================================
 *
 * @author Sorin Nasoi (sorin.nasoi@ipdevel.ro)
 * @file functions/StringsImpl.cpp
 *
 */

#include <iostream>

#include "runtime/strings/StringsImpl.h"
#include "util/tracer.h"
#include "types/casting.h"
#include "errors/Error.h"
#include "util/zorba.h"
#include "util/utf8/utf8.h"

using namespace std;
namespace xqp {
/**
 *______________________________________________________________________
 *
 *	7.2.1 fn:codepoints-to-string
 *
 *	fn:codepoints-to-string($arg as xs:integer*) as xs:string
 *
 *	Summary:Creates an xs:string from a sequence of code points.
 *Returns the zero-length string if $arg is the empty sequence.
 *If any of the code points in $arg is not a legal XML character,
 *an error is raised [err:FOCH0001] ("Code point not valid.").
 *_______________________________________________________________________*/
/* begin class CodepointsToStringIterator */
Item_t CodepointsToStringIterator::nextImpl(PlanState& planState){
	Item_t item;
	Item_t resItem;
	xqp_string resStr;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	while(true){
		item = consumeNext ( theChild, planState );
		if ( item != NULL ){
			item = item->getAtomizationValue();
			resStr += (uint32_t)item->getIntegerValue();
		}
		else{
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createString(resStr);
			STACK_PUSH2( resItem, state );
			break;
		}
	}
	STACK_END2();
}
/* end class CodepointsToStringIterator */

/**
 *______________________________________________________________________
 *
 *	7.2.2 fn:string-to-codepoints
 *
 *	fn:string-to-codepoints($arg as xs:string?) as xs:integer*
 *
 *	Summary: Returns the sequence of code points that constitute an
 *xs:string.
 *If $arg is a zero-length string or the empty sequence,
 *the empty sequence is returned.
 *_______________________________________________________________________*/
/* begin class StringToCodepointsIterator */
Item_t StringToCodepointsIterator::nextImpl(PlanState& planState){
/*
	Item_t item;
	Item_t resItem;
	xqp_string inputStr;
	std::vector<int> resVector;
	std::vector<int>::iterator iter;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	item = consumeNext ( theChild, planState );
	if ( item != NULL ){
		inputStr = item->getStringValue();
		resVector = inputStr.getCodepoints();
		for(iter = resVector.begin(); iter != resVector.end(); iter++){
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createInteger(*iter);
			STACK_PUSH2( resItem, state );
		}
	}
	STACK_END2();
*/
	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);
	STACK_END2();
}
/* end class StringToCodepointsIterator */

/**
 *______________________________________________________________________
 *	7.3.2 fn:compare
 * fn:compare($comparand1 as xs:string?,
 * 									$comparand2 as xs:string?) as xs:integer
 *
 * fn:compare( 	$comparand1	as xs:string?,
 * 										$comparand2	as xs:string?,
 * 										$collation	as xs:string) as xs:integer?
 *
 * Summary: Returns -1, 0, or 1, depending on whether the value of
 * the $comparand1 is respectively less than, equal to, or greater
 * than the value of $comparand2, according to the rules of
 * the collation that is used.
 *
 * If either argument is the empty sequence, the result is the empty sequence.
 *_______________________________________________________________________*/

/* begin class CompareStrIterator */
Item_t
CompareStrIterator::nextImpl(PlanState& planState) {
	Item_t n0;
	Item_t n1;
	Item_t n2;
	Item_t res;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

	n0 = consumeNext ( theChildren[0], planState );
	if ( n0 != NULL )	{
		n1 = consumeNext ( theChildren[1], planState );
		if ( n1 != NULL )	{
			n0 = n0->getAtomizationValue();
			n1 = n1->getAtomizationValue();
			n2 = consumeNext ( theChildren[2], planState );
			if(theChildren.size() == 3)	{
				if ( n2 != NULL )	{
					//TODO solve track issue no.26
					res = zorba::getZorbaForCurrentThread()->getItemFactory()->createInteger(
									n0->getStringValue().compare(n1->getStringValue(), n2->getStringValue().c_str()));
				}
			}
			else{
				res = zorba::getZorbaForCurrentThread()->getItemFactory()->createInteger(
								n0->getStringValue().compare(n1->getStringValue()));
			}
			STACK_PUSH2( res, state );
		}
	}

	STACK_END2();
}
/* end class CompareStrIterator */

/**
 *______________________________________________________________________
 *
 *	7.3.3 fn:codepoint-equal
 *
 *	fn:codepoint-equal( 	$comparand1 	 as xs:string?,
 *  											$comparand2 	 as xs:string?) as xs:boolean?
 *
 *	Summary: Returns true or false depending on whether the value
 * of $comparand1 is equal to the value of $comparand2, according to
 * the Unicode code point collation
 * (http://www.w3.org/2005/xpath-functions/collation/codepoint).
 *
 * If either argument is the empty sequence, the result is the empty sequence.
 *
 * Note: This function allows xs:anyURI values to be compared
 * without having to specify the Unicode code point collation.
 *_______________________________________________________________________*/
/* begin class CodepointEqualIterator */
Item_t CodepointEqualIterator::nextImpl(PlanState& planState){
		Item_t item0;
		Item_t item1;
		Item_t res;

		PlanIterator::PlanIteratorState* state;
		STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

		item0 = consumeNext ( theChild0, planState );
		if ( item0 != NULL )	{
			item1 = consumeNext ( theChild1, planState );
			if ( item1 != NULL )	{
				item0 = item0->getAtomizationValue();
				item1 = item1->getAtomizationValue();
				res = zorba::getZorbaForCurrentThread()->getItemFactory()->createBoolean(
									item0->getStringValue() == item1->getStringValue());
				STACK_PUSH2( res, state );
			}
		}
		STACK_END2();
}
/* end class CodepointEqualIterator */
/**
 *______________________________________________________________________
 *
 *	7.4.1 fn:concat
 *
 * fn:concat( 	$arg1 	 as xs:anyAtomicType?,
 * 									$arg2 	 as xs:anyAtomicType?,
 * 									...																					) as xs:string
 *
 * Summary:
 * Accepts two or more xs:anyAtomicType arguments and casts them to xs:string.
 * Returns the xs:string that is the concatenation of the values of its
 * arguments after conversion.
 * If any of the arguments is the empty sequence, the argument is treated
 * as the zero-length string.
 *
 * The fn:concat function is specified to allow an two or more arguments
 * that are concatenated together.
 *
 * Note:
 * Unicode normalization is not automatically applied to the result
 * of fn:concat. If a normalized result is required, fn:normalize-unicode
 * can be applied to the xs:string returned by fn:concat.
 *_______________________________________________________________________*/
/* begin class ConcatStrIterator */
Item_t ConcatStrIterator::nextImpl(PlanState& planState) {
	/*
	Item_t item;
	Item_t resItem;
	xqp_string resStr;

	int argsNo = theChildren.size();*/
	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);
/*
	while(true){
		item = consumeNext ( theChildren, planState );
		if ( item != NULL ){
			item = item->getAtomizationValue();
			resStr += item->getStringValue();
		}
		else{
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createString(resStr);
			STACK_PUSH2( resItem, state );
			break;
		}
	}*/
	STACK_END2();
}
/* end class ConcatStrIterator */

/**
 *______________________________________________________________________
 *
 *	7.4.2 fn:string-join
 *
 * fn:string-join($arg1 as xs:string*,
 * 										$arg2 as xs:string) as xs:string
 *
 * Summary: Returns a xs:string created by concatenating the members
 * of the $arg1 sequence using $arg2 as a separator.
 *
 * If the value of $arg2 is the zero-length string,
 * then the members of $arg1 are concatenated without a separator.
 *
 * If the value of $arg1 is the empty sequence,
 * the zero-length string is returned.
 *_______________________________________________________________________*/
/* begin class StringJoinIterator */
Item_t StringJoinIterator::nextImpl(PlanState& planState) {
	Item_t item;
	Item_t resItem;
	xqp_string resStr;
	xqp_string separator;

	PlanIterator::PlanIteratorState* state;
	STACK_INIT2(PlanIterator::PlanIteratorState, state, planState);

//TODO this is not correct:
//Step 1: find the separator based on the type (item not sequence)
//step 2: concatenate the items whithin the sequence using separator as "glue"
	while(true){
		item = consumeNext ( theChild0, planState );
		if ( item != NULL ){
			item = item->getAtomizationValue();
			resStr += item->getStringValue();
		}
		else{
			resItem = zorba::getZorbaForCurrentThread()->getItemFactory()->createString(resStr);
			STACK_PUSH2( resItem, state );
			break;
		}
	}
	STACK_END2();
}
/* end class StringJoinIterator */
} /* namespace xqp */
<|endoftext|>


<commit_before>#include <map>
#include <unordered_map>
#include <gtest/gtest.h>
#include "mmap_allocator.h"

using std::string;
using std::to_string;

namespace mm {

struct Foo {
  Foo(int x) : x(x) {}
  ~Foo() { y = x; }

  int x;
  static int y;
};

int Foo::y = 0;

class AllocatorTest : public testing::Test {
 protected:
  void SetUp() {
    if (!SetStorage("test.db")) {
      FAIL() << "Unable to create storage";
    }
  }
  void TearDown() {
    if (!Cleanup()) {
      FAIL() << "Unable to cleanup storage";
    }
  }
};

TEST_F(AllocatorTest, Allocate) {
  Allocator<int> alloc;
  int* p = alloc.allocate(1);
  ASSERT_FALSE(p == NULL);
  *p = 4;
  EXPECT_EQ(4, *p);

  alloc.deallocate(p, 1);
}

TEST_F(AllocatorTest, New) {
  Allocator<int> alloc;
  int* p = new (alloc) int(4);
  ASSERT_FALSE(p == NULL);
  EXPECT_EQ(*p, 4);
  *p = 42;
  EXPECT_EQ(*p, 42);

  alloc.deallocate(p, 1);
}

TEST_F(AllocatorTest, NewArray) {
  Allocator<int> alloc;
  int* p = new (alloc) int[10];
  p[9] = 42;
  EXPECT_EQ(p[9], 42);

  alloc.deallocate(p, 10);
}

TEST_F(AllocatorTest, NewConstructor) {
  Allocator<Foo> alloc;
  Foo* foo = new (alloc) Foo(49);
  EXPECT_EQ(49, foo->x);

  alloc.deallocate(foo, 1);
}

TEST_F(AllocatorTest, Destructor) {
  Allocator<Foo> alloc;
  Foo* foo = new (alloc) Foo(49);
  alloc.destroy(foo);
  alloc.deallocate(foo, 1);

  EXPECT_EQ(49, Foo::y);
}

TEST_F(AllocatorTest, VectorInt) {
  vector<int> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back(i);
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(i, vec[i]);
  }
}

TEST_F(AllocatorTest, VectorIntInitialized) {
  vector<int> vec{4, 42, 24, 7};

  EXPECT_EQ(4, vec.size());
  EXPECT_EQ(4, vec[0]);
  EXPECT_EQ(42, vec[1]);
  EXPECT_EQ(24, vec[2]);
  EXPECT_EQ(7, vec[3]);
}

TEST_F(AllocatorTest, VectorDouble) {
  vector<double> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back(sqrt(i));
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(sqrt(i), vec[i]);
  }
}

TEST_F(AllocatorTest, VectorString) {
  vector<string> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back("Hello, world!");
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ("Hello, world!", vec[i]);
  }
}

TEST_F(AllocatorTest, MapStringString) {
  map<string, string> m;

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(AllocatorTest, SetString) {
  set<string> s;

  s.insert("foo");
  s.insert("bar");

  EXPECT_EQ(2, s.size());
  EXPECT_EQ(1, s.count("foo"));
  EXPECT_EQ(1, s.count("bar"));
  EXPECT_EQ(0, s.count("baz"));
}

TEST_F(AllocatorTest, HashStringString) {
  unordered_map<string, string> m;

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(AllocatorTest, Nested) {
  unordered_map<string, vector<string>> m;
  EXPECT_EQ(0, m.size());

  for (int i = 0; i < 10; ++i) {
    m["foo"].push_back(to_string(i));
  }
  EXPECT_EQ(10, m["foo"].size());

  for (int i = 0; i < 10; ++i) {
    m["bar"].push_back(to_string(i * i));
  }
  EXPECT_EQ(10, m["bar"].size());

  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i), m["foo"][i]);
  }
  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i * i), m["bar"][i]);
  }
}

};  // namespace mm
<commit_msg>added some more tests<commit_after>#include <map>
#include <unordered_map>
#include <gtest/gtest.h>
#include "mmap_allocator.h"

using std::string;
using std::to_string;

namespace mm {

struct Foo {
  Foo(int x) : x(x) {}
  ~Foo() { y = x; }

  int x;
  static int y;
};

int Foo::y = 0;

class AllocatorTest : public testing::Test {
 protected:
  void SetUp() {
    if (!SetStorage("test.db")) {
      FAIL() << "Unable to create storage";
    }
  }
  void TearDown() {
    if (!Cleanup()) {
      FAIL() << "Unable to cleanup storage";
    }
  }
};

TEST_F(AllocatorTest, Allocate) {
  Allocator<int> alloc;
  int* p = alloc.allocate(1);
  ASSERT_FALSE(p == NULL);
  *p = 4;
  EXPECT_EQ(4, *p);

  alloc.deallocate(p, 1);
}

TEST_F(AllocatorTest, New) {
  Allocator<int> alloc;
  int* p = new (alloc) int(4);
  ASSERT_FALSE(p == NULL);
  EXPECT_EQ(*p, 4);
  *p = 42;
  EXPECT_EQ(*p, 42);

  alloc.deallocate(p, 1);
}

TEST_F(AllocatorTest, NewArray) {
  Allocator<int> alloc;
  int* p = new (alloc) int[10];
  p[9] = 42;
  EXPECT_EQ(p[9], 42);

  alloc.deallocate(p, 10);
}

TEST_F(AllocatorTest, NewConstructor) {
  Allocator<Foo> alloc;
  Foo* foo = new (alloc) Foo(49);
  EXPECT_EQ(49, foo->x);

  alloc.deallocate(foo);
}

TEST_F(AllocatorTest, Destructor) {
  Allocator<Foo> alloc;
  Foo* foo = new (alloc) Foo(49);
  alloc.destroy(foo);
  alloc.deallocate(foo, 1);

  EXPECT_EQ(49, Foo::y);
}

TEST_F(AllocatorTest, VectorInt) {
  vector<int> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back(i);
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(i, vec[i]);
  }
}

TEST_F(AllocatorTest, VectorIntInitialized) {
  vector<int> vec{4, 42, 24, 7};

  EXPECT_EQ(4, vec.size());
  EXPECT_EQ(4, vec[0]);
  EXPECT_EQ(42, vec[1]);
  EXPECT_EQ(24, vec[2]);
  EXPECT_EQ(7, vec[3]);
}

TEST_F(AllocatorTest, VectorDouble) {
  vector<double> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back(sqrt(i));
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(sqrt(i), vec[i]);
  }
}

TEST_F(AllocatorTest, VectorString) {
  vector<string> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back("Hello, world!");
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ("Hello, world!", vec[i]);
  }
}

TEST_F(AllocatorTest, MapStringString) {
  map<string, string> m;

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(AllocatorTest, SetString) {
  set<string> s;

  s.insert("foo");
  s.insert("bar");

  EXPECT_EQ(2, s.size());
  EXPECT_EQ(1, s.count("foo"));
  EXPECT_EQ(1, s.count("bar"));
  EXPECT_EQ(0, s.count("baz"));
}

TEST_F(AllocatorTest, HashStringString) {
  unordered_map<string, string> m;

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(AllocatorTest, Nested) {
  unordered_map<string, vector<string>> m;
  EXPECT_EQ(0, m.size());

  for (int i = 0; i < 10; ++i) {
    m["foo"].push_back(to_string(i));
  }
  EXPECT_EQ(10, m["foo"].size());

  for (int i = 0; i < 10; ++i) {
    m["bar"].push_back(to_string(i * i));
  }
  EXPECT_EQ(10, m["bar"].size());

  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i), m["foo"][i]);
  }
  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i * i), m["bar"][i]);
  }
}

};  // namespace mm
<|endoftext|>


<commit_before>#include "sample.hpp"

class HelloSample : public Sample
{
public:
	virtual bool initContents()
	{
		return true;
	}

	virtual void destroyContents()
	{
	}

	virtual void update(float dt)
	{
	}

	virtual void render()
	{
	}
};

int main(int argc, char** argv)
{
	auto helloSample = new HelloSample();
	helloSample->init();

	helloSample->run();

	helloSample->destroy();

	if (helloSample) {
		delete helloSample;
		helloSample = nullptr;
	}

	return 0;
}
<commit_msg>Write sampleframwork test<commit_after>#include "sample.hpp"

#include <cstdio>
#include <cstdlib>

#include <signal.h>

class HelloSample : public Sample
{
public:
	virtual bool initContents()
	{
		return true;
	}

	virtual void destroyContents()
	{
	}

	virtual void update(float dt)
	{
	}

	virtual void render()
	{
	}
};

Sample* helloSample = nullptr;

void funCatch(int signal)
{
	if (helloSample == nullptr)
		return;

	helloSample->destroy();

	if (helloSample) {
		delete helloSample;
		helloSample = nullptr;
	}

	printf("interrupted!\n");

	exit(EXIT_SUCCESS);
}

int main(int argc, char** argv)
{
	if (signal(SIGINT, funCatch) == SIG_ERR) {
		fprintf(stderr, "cannot catch signal\n");
	}

	helloSample = new HelloSample();
	helloSample->init();

	helloSample->run();

	helloSample->destroy();

	if (helloSample) {
		delete helloSample;
		helloSample = nullptr;
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
    Copyright(c) Microsoft Open Technologies, Inc. All rights reserved.

    The MIT License(MIT)

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files(the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions :

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/

#include "pch.h"
#include "TwoWire.h"

using namespace Microsoft::Maker::Firmata;
using namespace Microsoft::Maker::RemoteWiring::I2c;

void
TwoWire::enable(
    uint16_t i2cReadDelayMicros_
    )
{
	i2cReadDelayMicros_ = (i2cReadDelayMicros_ > MAX_READ_DELAY_MICROS) ? MAX_READ_DELAY_MICROS : i2cReadDelayMicros_;

    _firmata->beginSysex( static_cast<uint8_t>( SysexCommand::I2C_CONFIG ) );
    _firmata->appendSysex( i2cReadDelayMicros_ );
	_firmata->endSysex();
}

void
TwoWire::beginTransmission(
    uint8_t address_
    )
{
    if( _address ) return;
    _address = address_;
    _position = 0;
}

void
TwoWire::write(
    uint8_t data_
    )
{
    if( !_address || _position > MAX_MESSAGE_LEN ) return;
    _data_buffer.get()[_position] = data_;
    ++_position;
}

void
TwoWire::endTransmission(
    void
    )
{
    if( !_address ) return;
    sendI2cSysex( _address, 0, _position, _data_buffer.get() );
    _address = 0;
    _position = 0;
}

//******************************************************************************
//* Private Methods
//******************************************************************************

void
TwoWire::sendI2cSysex(
    const uint8_t address_,
    const uint8_t rw_mask_,
    const uint8_t len_,
    uint8_t *data_
    )
{
    _firmata->lock();
    try
    {
        _firmata->write( static_cast<uint8_t>( Command::START_SYSEX ) );
        _firmata->write( static_cast<uint8_t>( Microsoft::Maker::Firmata::SysexCommand::I2C_REQUEST ) );
        _firmata->write( address_ );
        _firmata->write( rw_mask_ );

        if( data_ != nullptr )
        {
            for( size_t i = 0; i < len_; ++i )
            {
                _firmata->sendValueAsTwo7bitBytes( data_[i] );
            }
        }

        _firmata->write( static_cast<uint8_t>( Command::END_SYSEX ) );
        _firmata->flush();
        _firmata->unlock();
    }
    catch( ... )
    {
        _firmata->unlock();
    }
}

void
TwoWire::onI2cReply(
    I2cCallbackEventArgs ^args
    )
{
    I2cReplyEvent( args->getAddress(), args->getRegister(), Windows::Storage::Streams::DataReader::FromBuffer( args->getDataBuffer() ) );
}
<commit_msg>Replaced logic in TwoWire to use the new sendSysex model.<commit_after>/*
    Copyright(c) Microsoft Open Technologies, Inc. All rights reserved.

    The MIT License(MIT)

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files(the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions :

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/

#include "pch.h"
#include "TwoWire.h"

using namespace Microsoft::Maker::Firmata;
using namespace Microsoft::Maker::RemoteWiring::I2c;

void
TwoWire::enable(
    uint16_t i2cReadDelayMicros_
    )
{
	i2cReadDelayMicros_ = (i2cReadDelayMicros_ > MAX_READ_DELAY_MICROS) ? MAX_READ_DELAY_MICROS : i2cReadDelayMicros_;

    using Windows::Storage::Streams::DataWriter;
    DataWriter ^writer = ref new DataWriter();
    writer->WriteByte( i2cReadDelayMicros_ & 0x7F );
    writer->WriteByte( ( i2cReadDelayMicros_ >> 7 ) & 0x7F );

    _firmata->sendSysex( SysexCommand::I2C_CONFIG, writer->DetachBuffer() );
}

void
TwoWire::beginTransmission(
    uint8_t address_
    )
{
    if( _address ) return;
    _address = address_;
    _position = 0;
}

void
TwoWire::write(
    uint8_t data_
    )
{
    if( !_address || _position > MAX_MESSAGE_LEN ) return;
    _data_buffer.get()[_position] = data_;
    ++_position;
}

void
TwoWire::endTransmission(
    void
    )
{
    if( !_address ) return;
    sendI2cSysex( _address, 0, _position, _data_buffer.get() );
    _address = 0;
    _position = 0;
}

//******************************************************************************
//* Private Methods
//******************************************************************************

void
TwoWire::sendI2cSysex(
    const uint8_t address_,
    const uint8_t rw_mask_,
    const uint8_t len_,
    uint8_t *data_
    )
{
    _firmata->lock();
    try
    {
        _firmata->write( static_cast<uint8_t>( Command::START_SYSEX ) );
        _firmata->write( static_cast<uint8_t>( Microsoft::Maker::Firmata::SysexCommand::I2C_REQUEST ) );
        _firmata->write( address_ );
        _firmata->write( rw_mask_ );

        if( data_ != nullptr )
        {
            for( size_t i = 0; i < len_; ++i )
            {
                _firmata->sendValueAsTwo7bitBytes( data_[i] );
            }
        }

        _firmata->write( static_cast<uint8_t>( Command::END_SYSEX ) );
        _firmata->flush();
        _firmata->unlock();
    }
    catch( ... )
    {
        _firmata->unlock();
    }
}

void
TwoWire::onI2cReply(
    I2cCallbackEventArgs ^args
    )
{
    I2cReplyEvent( args->getAddress(), args->getRegister(), Windows::Storage::Streams::DataReader::FromBuffer( args->getDataBuffer() ) );
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cmath>

using namespace std;
double E = 0.0001;

void bairstow( double *arr, double *arrOr, int size, double r, double s ) {
    arr[size-1] = arrOr[size-1];
    arr[size-2] = arr[size-1] * r + arrOr[size-2];

    for ( int i = size - 3; i >= 0; i-- ) {
        arr[i] = ( arr[i + 1] * r ) + ( arr[i + 2] * s ) + arrOr[i];
    }
    return;
}

int main() {
    double arrVal[] = {2, -10, 10, 5, -5, 15};
    int size = sizeof(arrVal) / sizeof(arrVal[0]);
    int count = 1;

    double arrB[size];
    double arrC[size];

    double r = -1;
    double s = -1;

    double dr;
    double ds;

    do {
        bairstow( arrB, arrVal, size, r, s );
        bairstow( arrC, arrB, size, r, s );
        dr = ( -arrB[1] * arrC[2] - arrC[3] * -arrB[0] ) / ( arrC[2] * arrC[2] - arrC[1] * arrC[3] );
        ds = ( -arrB[0] * arrC[2] - arrC[1] * -arrB[1] ) / ( arrC[2] * arrC[2] - arrC[1] * arrC[3] );

        double errorR = ( dr / r ) * 100;
        double errorS = ( ds / s ) * 100;

        if ( abs(errorR) <= E && abs(errorS) <= E ) {
            break;
        }
        r += dr;
        s += ds;
        count++;
    } while (true);

    double x1 = ( r + sqrt( r * r + 4 * s ) ) / 2;
    double x2 = ( r - sqrt( r * r + 4 * s ) ) / 2;

    cout << "Root 1: " << x1 << endl
    << "Root 2: " << x2 << endl;

    cout << "r: " << r << endl
    << "s: " << s << endl;

    for ( int i = 0; i < size; i++ ) {
        cout << "Coeficientes de la funcion con menor grado " << arrC[i] << endl;
    }
    return 0;
}
<commit_msg>Update Bairstow.cpp<commit_after>#include<iostream>
#include<cmath>

using namespace std;

void Bairstow(float r, float s, float array[], int grado){
	float b[grado+1];
    float c[grado+1];
    b[0]= array[0];
    b[1] = array[1]+(b[0]*r);
    b[2] = array[2]+(b[1]*r)+(b[0]*s);
    for (int i = 3; i < grado+1; ++i)
    {
        b[i] = array[i] + (b[i-1]*r) + (b[i-2]*s);
    }

    cout << "-----b-----" << endl;
    for (int i = 0; i < grado+1; ++i)
    {
        cout << b[i] <<endl;
    }
    cout << "----------" << endl;

    c[0]= b[0];
    c[1] = b[1]+(c[0]*r);
    c[2] = b[2]+(c[1]*r)+(c[0]*s);
    for (int i = 3; i < grado+1; ++i)
    {
        c[i] = b[i] + (c[i-1]*r) + (c[i-2]*s);
    }

    cout << "-----c-----" << endl;
    for (int i = 0; i < grado+1; ++i)
    {
        cout << c[i] <<endl;
    }
    cout << "----------" << endl;

    float A = c[grado-2];
    float B = c[grado-3];
    float C = -b[grado-1];
    float P = c[grado-1];
    float Q = c[grado-2];
    float R = -b[grado];

    float deltaR = ((C*Q)-(B*R))/((A*Q)-(P*B));
    float deltaS = ((A*R)-(C*P))/((A*Q)-(P*B));
    cout << "deltaR" << deltaR << endl;
    cout << "deltaS" << deltaS << endl;

    r += deltaR;
    s += deltaS;
    cout << "nueva r: " << r <<endl;
    cout << "nueva s: " << s <<endl;

    float errorR = abs(deltaR/r)*100;
    float errorS = abs(deltaS/s)*100;

    cout << "ErrorR: " << errorR << endl;
    cout << "ErrorS: " << errorS << endl;

    int counter = 0;

    while (errorR >= .01 || errorS >= .01){
        b[0]= array[0];
        b[1] = array[1]+(b[0]*r);
        b[2] = array[2]+(b[1]*r)+(b[0]*s);
        for (int i = 3; i < grado+1; ++i)
        {
            b[i] = array[i] + (b[i-1]*r) + (b[i-2]*s);
        }

        cout << "-----b-----" << endl;
        for (int i = 0; i < grado+1; ++i)
        {
            cout << b[i] <<endl;
        }
        cout << "----------" << endl;

        c[0]= b[0];
        c[1] = b[1]+(c[0]*r);
        c[2] = b[2]+(c[1]*r)+(c[0]*s);
        for (int i = 3; i < grado+1; ++i)
        {
            c[i] = b[i] + (c[i-1]*r) + (c[i-2]*s);
        }

        cout << "-----c-----" << endl;
        for (int i = 0; i < grado+1; ++i)
        {
            cout << c[i] <<endl;
        }
        cout << "----------" << endl;

        A = c[grado-2];
        B = c[grado-3];
        C = -b[grado-1];
        P = c[grado-1];
        Q = c[grado-2];
        R = -b[grado];

        deltaR = ((C*Q)-(B*R))/((A*Q)-(P*B));
        deltaS = ((A*R)-(C*P))/((A*Q)-(P*B));
        cout << "deltaR" << deltaR << endl;
        cout << "deltaS" << deltaS << endl;

        r += deltaR;
        s += deltaS;
        cout << "nueva r: " << r <<endl;
        cout << "nueva s: " << s <<endl;

        errorR = abs(deltaR/r);
        errorS = abs(deltaS/s);

        cout << "ErrorR: " << errorR << endl;
        cout << "ErrorS: " << errorS << endl;

        counter++;
    }

    float x1 = (r+sqrt(pow(r,2)+(4*s)))/2;
    float x2 = (r-sqrt(pow(r,2)+(4*s)))/2;
    cout << "----RAICES-----" << endl;
    cout << "x1: " << x1 << endl;
    cout << "x2: " << x2 << endl;

    cout << "-----FIN-----" << endl;
    for (int i = 0; i < grado-1; ++i)
    {
        cout << b[i] <<endl;
    }
    cout << "----ITERACIONES-----" << endl;
    cout << counter << endl;
}

int main(){
    float arreglo[] = {15, -12.8709, 17.9903, -4.78701};
    int size = sizeof(arreglo)/sizeof(arreglo[0]);
    int grado = size-1;
    cout << "Grado = " << grado << endl;
    float r = -0.526994;
    float s = 0.413887;

    Bairstow(r,s,arreglo,grado);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chrome_browser_field_trials.h"

#include <string>

#include "apps/field_trial_names.h"
#include "apps/pref_names.h"
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_service.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/auto_launch_trial.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/gpu/chrome_gpu_util.h"
#include "chrome/browser/omnibox/omnibox_field_trial.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/ui/sync/one_click_signin_helper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/metrics/variations/uniformity_field_trials.h"
#include "chrome/common/metrics/variations/variations_util.h"
#include "chrome/common/pref_names.h"
#include "net/spdy/spdy_session.h"
#include "ui/base/layout.h"

#if defined(OS_WIN)
#include "net/socket/tcp_client_socket_win.h"
#endif  // defined(OS_WIN)

ChromeBrowserFieldTrials::ChromeBrowserFieldTrials(
    const CommandLine& parsed_command_line)
    : parsed_command_line_(parsed_command_line) {
}

ChromeBrowserFieldTrials::~ChromeBrowserFieldTrials() {
}

void ChromeBrowserFieldTrials::SetupFieldTrials(PrefService* local_state) {
  const base::Time install_time = base::Time::FromTimeT(
      local_state->GetInt64(prefs::kInstallDate));
  DCHECK(!install_time.is_null());
  chrome_variations::SetupUniformityFieldTrials(install_time);
  SetUpSimpleCacheFieldTrial();
#if !defined(OS_ANDROID) && !defined(OS_IOS)
  SetupDesktopFieldTrials(local_state);
#endif  // defined(OS_ANDROID)

#if defined(OS_ANDROID) || defined(OS_IOS)
  SetupMobileFieldTrials();
#endif  // defined(OS_ANDROID) || defined(OS_IOS)
}

#if defined(OS_ANDROID) || defined(OS_IOS)
void ChromeBrowserFieldTrials::SetupMobileFieldTrials() {
  DataCompressionProxyFieldTrial();
}

// Governs the rollout of the compression proxy for Chrome on mobile platforms.
// Always enabled in DEV and BETA versions.
// Stable percentage will be controlled from server.
void ChromeBrowserFieldTrials::DataCompressionProxyFieldTrial() {
  const char kDataCompressionProxyFieldTrialName[] =
      "DataCompressionProxyRollout";
  const base::FieldTrial::Probability kDataCompressionProxyDivisor = 1000;

  // 10/1000 = 1% for starters.
  const base::FieldTrial::Probability kDataCompressionProxyStable = 10;
  const char kEnabled[] = "Enabled";
  const char kDisabled[] = "Disabled";

  // Find out if this is a stable channel.
  const bool kIsStableChannel =
      chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE;

  // Experiment enabled until Jan 1, 2015. By default, disabled.
  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial(
          kDataCompressionProxyFieldTrialName, kDataCompressionProxyDivisor,
          kDisabled, 2015, 1, 1, NULL));

  // We want our trial results to be persistent.
  trial->UseOneTimeRandomization();
  // Non-stable channels will run with probability 1.
  const int kEnabledGroup = trial->AppendGroup(
      kEnabled,
      kIsStableChannel ?
          kDataCompressionProxyStable : kDataCompressionProxyDivisor);

  const int v = trial->group();
  VLOG(1) << "DataCompression proxy enabled group id: " << kEnabledGroup
          << ". Selected group id: " << v;
}
#endif  // defined(OS_ANDROID) || defined(OS_IOS)

void ChromeBrowserFieldTrials::SetupDesktopFieldTrials(
    PrefService* local_state) {
  prerender::ConfigurePrefetchAndPrerender(parsed_command_line_);
  SpdyFieldTrial();
  AutoLaunchChromeFieldTrial();
  gpu_util::InitializeCompositingFieldTrial();
  OmniboxFieldTrial::ActivateStaticTrials();
  SetUpInfiniteCacheFieldTrial();
  SetUpCacheSensitivityAnalysisFieldTrial();
  DisableShowProfileSwitcherTrialIfNecessary();
  WindowsOverlappedTCPReadsFieldTrial();
#if defined(ENABLE_ONE_CLICK_SIGNIN)
  OneClickSigninHelper::InitializeFieldTrial();
#endif
  InstantiateDynamicTrials();
  SetupAppLauncherFieldTrial(local_state);
}

void ChromeBrowserFieldTrials::SetupAppLauncherFieldTrial(
    PrefService* local_state) {
  if (base::FieldTrialList::FindFullName(apps::kLauncherPromoTrialName) ==
      apps::kResetShowLauncherPromoPrefGroupName) {
    local_state->SetBoolean(apps::prefs::kShowAppLauncherPromo, true);
  }
}

// When --use-spdy not set, users will be in A/B test for spdy.
// group A (npn_with_spdy): this means npn and spdy are enabled. In case server
//                          supports spdy, browser will use spdy.
// group B (npn_with_http): this means npn is enabled but spdy won't be used.
//                          Http is still used for all requests.
//           default group: no npn or spdy is involved. The "old" non-spdy
//                          chrome behavior.
void ChromeBrowserFieldTrials::SpdyFieldTrial() {
  // Setup SPDY CWND Field trial.
  const base::FieldTrial::Probability kSpdyCwndDivisor = 100;
  const base::FieldTrial::Probability kSpdyCwnd16 = 20;     // fixed at 16
  const base::FieldTrial::Probability kSpdyCwnd10 = 20;     // fixed at 10
  const base::FieldTrial::Probability kSpdyCwndMin16 = 20;  // no less than 16
  const base::FieldTrial::Probability kSpdyCwndMin10 = 20;  // no less than 10

  // After June 30, 2013 builds, it will always be in default group
  // (cwndDynamic).
  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial(
          "SpdyCwnd", kSpdyCwndDivisor, "cwndDynamic", 2013, 6, 30, NULL));

  trial->AppendGroup("cwnd10", kSpdyCwnd10);
  trial->AppendGroup("cwnd16", kSpdyCwnd16);
  trial->AppendGroup("cwndMin16", kSpdyCwndMin16);
  trial->AppendGroup("cwndMin10", kSpdyCwndMin10);
}

void ChromeBrowserFieldTrials::AutoLaunchChromeFieldTrial() {
  std::string brand;
  google_util::GetBrand(&brand);

  // Create a 100% field trial based on the brand code.
  if (auto_launch_trial::IsInExperimentGroup(brand)) {
    base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
                                           kAutoLaunchTrialAutoLaunchGroup);
  } else if (auto_launch_trial::IsInControlGroup(brand)) {
    base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
                                           kAutoLaunchTrialControlGroup);
  }
}

void ChromeBrowserFieldTrials::SetUpInfiniteCacheFieldTrial() {
  const base::FieldTrial::Probability kDivisor = 100;

  base::FieldTrial::Probability infinite_cache_probability = 0;

  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial("InfiniteCache", kDivisor,
                                                 "No", 2013, 12, 31, NULL));
  trial->UseOneTimeRandomization();
  trial->AppendGroup("Yes", infinite_cache_probability);
  trial->AppendGroup("Control", infinite_cache_probability);
}

void ChromeBrowserFieldTrials::DisableShowProfileSwitcherTrialIfNecessary() {
  // This trial is created by the VariationsService, but it needs to be disabled
  // if multi-profiles isn't enabled or if browser frame avatar menu is
  // always hidden (Chrome OS).
  bool avatar_menu_always_hidden = false;
#if defined(OS_CHROMEOS)
  avatar_menu_always_hidden = true;
#endif
  base::FieldTrial* trial = base::FieldTrialList::Find("ShowProfileSwitcher");
  if (trial && (!ProfileManager::IsMultipleProfilesEnabled() ||
                avatar_menu_always_hidden)) {
    trial->Disable();
  }
}

// Sets up the experiment. The actual cache backend choice is made in the net/
// internals by looking at the experiment state.
void ChromeBrowserFieldTrials::SetUpSimpleCacheFieldTrial() {
  if (parsed_command_line_.HasSwitch(switches::kUseSimpleCacheBackend)) {
    const std::string opt_value = parsed_command_line_.GetSwitchValueASCII(
        switches::kUseSimpleCacheBackend);
    if (LowerCaseEqualsASCII(opt_value, "off")) {
      // This is the default.
      return;
    }
    const base::FieldTrial::Probability kDivisor = 100;
    scoped_refptr<base::FieldTrial> trial(
        base::FieldTrialList::FactoryGetFieldTrial("SimpleCacheTrial", kDivisor,
                                                   "No", 2013, 12, 31, NULL));
    trial->UseOneTimeRandomization();
    if (LowerCaseEqualsASCII(opt_value, "on")) {
      trial->AppendGroup("Yes", 100);
      return;
    }
#if defined(OS_ANDROID)
    if (LowerCaseEqualsASCII(opt_value, "experiment")) {
      // TODO(pasko): Make this the default on Android when the simple cache
      // adds a few more necessary features. Also adjust the probability.
      const base::FieldTrial::Probability kSimpleCacheProbability = 1;
      trial->AppendGroup("Yes", kSimpleCacheProbability);
      trial->AppendGroup("Control", kSimpleCacheProbability);
      trial->group();
    }
#endif
  }
}

void ChromeBrowserFieldTrials::SetUpCacheSensitivityAnalysisFieldTrial() {
  const base::FieldTrial::Probability kDivisor = 100;

  base::FieldTrial::Probability sensitivity_analysis_probability = 0;

  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial("CacheSensitivityAnalysis",
                                                 kDivisor, "No",
                                                 2012, 12, 31, NULL));
  trial->AppendGroup("ControlA", sensitivity_analysis_probability);
  trial->AppendGroup("ControlB", sensitivity_analysis_probability);
  trial->AppendGroup("100A", sensitivity_analysis_probability);
  trial->AppendGroup("100B", sensitivity_analysis_probability);
  trial->AppendGroup("200A", sensitivity_analysis_probability);
  trial->AppendGroup("200B", sensitivity_analysis_probability);
  trial->AppendGroup("400A", sensitivity_analysis_probability);
  trial->AppendGroup("400B", sensitivity_analysis_probability);
}

void ChromeBrowserFieldTrials::WindowsOverlappedTCPReadsFieldTrial() {
#if defined(OS_WIN)
  if (parsed_command_line_.HasSwitch(switches::kOverlappedRead)) {
    std::string option =
        parsed_command_line_.GetSwitchValueASCII(switches::kOverlappedRead);
    if (LowerCaseEqualsASCII(option, "off"))
      net::TCPClientSocketWin::DisableOverlappedReads();
  } else {
    const base::FieldTrial::Probability kDivisor = 2;  // 1 in 2 chance
    const base::FieldTrial::Probability kOverlappedReadProbability = 1;
    scoped_refptr<base::FieldTrial> overlapped_reads_trial(
        base::FieldTrialList::FactoryGetFieldTrial("OverlappedReadImpact",
            kDivisor, "OverlappedReadEnabled", 2013, 6, 1, NULL));
    int overlapped_reads_disabled_group =
        overlapped_reads_trial->AppendGroup("OverlappedReadDisabled",
                                            kOverlappedReadProbability);
    int assigned_group = overlapped_reads_trial->group();
    if (assigned_group == overlapped_reads_disabled_group)
      net::TCPClientSocketWin::DisableOverlappedReads();
  }
#endif
}

void ChromeBrowserFieldTrials::InstantiateDynamicTrials() {
  // Call |FindValue()| on the trials below, which may come from the server, to
  // ensure they get marked as "used" for the purposes of data reporting.
  base::FieldTrialList::FindValue("UMA-Dynamic-Binary-Uniformity-Trial");
  base::FieldTrialList::FindValue("UMA-Dynamic-Uniformity-Trial");
  base::FieldTrialList::FindValue("InstantDummy");
  base::FieldTrialList::FindValue("InstantChannel");
  base::FieldTrialList::FindValue("Test0PercentDefault");
  // Activate the autocomplete dynamic field trials.
  OmniboxFieldTrial::ActivateDynamicTrials();
}
<commit_msg>Enable cache sensitivity experiment in Android.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chrome_browser_field_trials.h"

#include <string>

#include "apps/field_trial_names.h"
#include "apps/pref_names.h"
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_service.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/auto_launch_trial.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/gpu/chrome_gpu_util.h"
#include "chrome/browser/omnibox/omnibox_field_trial.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/ui/sync/one_click_signin_helper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/metrics/variations/uniformity_field_trials.h"
#include "chrome/common/metrics/variations/variations_util.h"
#include "chrome/common/pref_names.h"
#include "net/spdy/spdy_session.h"
#include "ui/base/layout.h"

#if defined(OS_WIN)
#include "net/socket/tcp_client_socket_win.h"
#endif  // defined(OS_WIN)

ChromeBrowserFieldTrials::ChromeBrowserFieldTrials(
    const CommandLine& parsed_command_line)
    : parsed_command_line_(parsed_command_line) {
}

ChromeBrowserFieldTrials::~ChromeBrowserFieldTrials() {
}

void ChromeBrowserFieldTrials::SetupFieldTrials(PrefService* local_state) {
  const base::Time install_time = base::Time::FromTimeT(
      local_state->GetInt64(prefs::kInstallDate));
  DCHECK(!install_time.is_null());
  chrome_variations::SetupUniformityFieldTrials(install_time);
  SetUpSimpleCacheFieldTrial();
#if !defined(OS_ANDROID) && !defined(OS_IOS)
  SetupDesktopFieldTrials(local_state);
#endif  // defined(OS_ANDROID)

#if defined(OS_ANDROID) || defined(OS_IOS)
  SetupMobileFieldTrials();
#endif  // defined(OS_ANDROID) || defined(OS_IOS)
}

#if defined(OS_ANDROID) || defined(OS_IOS)
void ChromeBrowserFieldTrials::SetupMobileFieldTrials() {
  DataCompressionProxyFieldTrial();
}

// Governs the rollout of the compression proxy for Chrome on mobile platforms.
// Always enabled in DEV and BETA versions.
// Stable percentage will be controlled from server.
void ChromeBrowserFieldTrials::DataCompressionProxyFieldTrial() {
  const char kDataCompressionProxyFieldTrialName[] =
      "DataCompressionProxyRollout";
  const base::FieldTrial::Probability kDataCompressionProxyDivisor = 1000;

  // 10/1000 = 1% for starters.
  const base::FieldTrial::Probability kDataCompressionProxyStable = 10;
  const char kEnabled[] = "Enabled";
  const char kDisabled[] = "Disabled";

  // Find out if this is a stable channel.
  const bool kIsStableChannel =
      chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE;

  // Experiment enabled until Jan 1, 2015. By default, disabled.
  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial(
          kDataCompressionProxyFieldTrialName, kDataCompressionProxyDivisor,
          kDisabled, 2015, 1, 1, NULL));

  // We want our trial results to be persistent.
  trial->UseOneTimeRandomization();
  // Non-stable channels will run with probability 1.
  const int kEnabledGroup = trial->AppendGroup(
      kEnabled,
      kIsStableChannel ?
          kDataCompressionProxyStable : kDataCompressionProxyDivisor);

  const int v = trial->group();
  VLOG(1) << "DataCompression proxy enabled group id: " << kEnabledGroup
          << ". Selected group id: " << v;
}
#endif  // defined(OS_ANDROID) || defined(OS_IOS)

void ChromeBrowserFieldTrials::SetupDesktopFieldTrials(
    PrefService* local_state) {
  prerender::ConfigurePrefetchAndPrerender(parsed_command_line_);
  SpdyFieldTrial();
  AutoLaunchChromeFieldTrial();
  gpu_util::InitializeCompositingFieldTrial();
  OmniboxFieldTrial::ActivateStaticTrials();
  SetUpInfiniteCacheFieldTrial();
  SetUpCacheSensitivityAnalysisFieldTrial();
  DisableShowProfileSwitcherTrialIfNecessary();
  WindowsOverlappedTCPReadsFieldTrial();
#if defined(ENABLE_ONE_CLICK_SIGNIN)
  OneClickSigninHelper::InitializeFieldTrial();
#endif
  InstantiateDynamicTrials();
  SetupAppLauncherFieldTrial(local_state);
}

void ChromeBrowserFieldTrials::SetupAppLauncherFieldTrial(
    PrefService* local_state) {
  if (base::FieldTrialList::FindFullName(apps::kLauncherPromoTrialName) ==
      apps::kResetShowLauncherPromoPrefGroupName) {
    local_state->SetBoolean(apps::prefs::kShowAppLauncherPromo, true);
  }
}

// When --use-spdy not set, users will be in A/B test for spdy.
// group A (npn_with_spdy): this means npn and spdy are enabled. In case server
//                          supports spdy, browser will use spdy.
// group B (npn_with_http): this means npn is enabled but spdy won't be used.
//                          Http is still used for all requests.
//           default group: no npn or spdy is involved. The "old" non-spdy
//                          chrome behavior.
void ChromeBrowserFieldTrials::SpdyFieldTrial() {
  // Setup SPDY CWND Field trial.
  const base::FieldTrial::Probability kSpdyCwndDivisor = 100;
  const base::FieldTrial::Probability kSpdyCwnd16 = 20;     // fixed at 16
  const base::FieldTrial::Probability kSpdyCwnd10 = 20;     // fixed at 10
  const base::FieldTrial::Probability kSpdyCwndMin16 = 20;  // no less than 16
  const base::FieldTrial::Probability kSpdyCwndMin10 = 20;  // no less than 10

  // After June 30, 2013 builds, it will always be in default group
  // (cwndDynamic).
  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial(
          "SpdyCwnd", kSpdyCwndDivisor, "cwndDynamic", 2013, 6, 30, NULL));

  trial->AppendGroup("cwnd10", kSpdyCwnd10);
  trial->AppendGroup("cwnd16", kSpdyCwnd16);
  trial->AppendGroup("cwndMin16", kSpdyCwndMin16);
  trial->AppendGroup("cwndMin10", kSpdyCwndMin10);
}

void ChromeBrowserFieldTrials::AutoLaunchChromeFieldTrial() {
  std::string brand;
  google_util::GetBrand(&brand);

  // Create a 100% field trial based on the brand code.
  if (auto_launch_trial::IsInExperimentGroup(brand)) {
    base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
                                           kAutoLaunchTrialAutoLaunchGroup);
  } else if (auto_launch_trial::IsInControlGroup(brand)) {
    base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
                                           kAutoLaunchTrialControlGroup);
  }
}

void ChromeBrowserFieldTrials::SetUpInfiniteCacheFieldTrial() {
  const base::FieldTrial::Probability kDivisor = 100;

  base::FieldTrial::Probability infinite_cache_probability = 0;

  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial("InfiniteCache", kDivisor,
                                                 "No", 2013, 12, 31, NULL));
  trial->UseOneTimeRandomization();
  trial->AppendGroup("Yes", infinite_cache_probability);
  trial->AppendGroup("Control", infinite_cache_probability);
}

void ChromeBrowserFieldTrials::DisableShowProfileSwitcherTrialIfNecessary() {
  // This trial is created by the VariationsService, but it needs to be disabled
  // if multi-profiles isn't enabled or if browser frame avatar menu is
  // always hidden (Chrome OS).
  bool avatar_menu_always_hidden = false;
#if defined(OS_CHROMEOS)
  avatar_menu_always_hidden = true;
#endif
  base::FieldTrial* trial = base::FieldTrialList::Find("ShowProfileSwitcher");
  if (trial && (!ProfileManager::IsMultipleProfilesEnabled() ||
                avatar_menu_always_hidden)) {
    trial->Disable();
  }
}

// Sets up the experiment. The actual cache backend choice is made in the net/
// internals by looking at the experiment state.
void ChromeBrowserFieldTrials::SetUpSimpleCacheFieldTrial() {
  if (parsed_command_line_.HasSwitch(switches::kUseSimpleCacheBackend)) {
    const std::string opt_value = parsed_command_line_.GetSwitchValueASCII(
        switches::kUseSimpleCacheBackend);
    if (LowerCaseEqualsASCII(opt_value, "off")) {
      // This is the default.
      return;
    }
    const base::FieldTrial::Probability kDivisor = 100;
    scoped_refptr<base::FieldTrial> trial(
        base::FieldTrialList::FactoryGetFieldTrial("SimpleCacheTrial", kDivisor,
                                                   "No", 2013, 12, 31, NULL));
    trial->UseOneTimeRandomization();
    if (LowerCaseEqualsASCII(opt_value, "on")) {
      trial->AppendGroup("Yes", 100);
      return;
    }
#if defined(OS_ANDROID)
    if (LowerCaseEqualsASCII(opt_value, "experiment")) {
      // TODO(pasko): Make this the default on Android when the simple cache
      // adds a few more necessary features. Also adjust the probability.
      const base::FieldTrial::Probability kSimpleCacheProbability = 1;
      trial->AppendGroup("Yes", kSimpleCacheProbability);
      trial->AppendGroup("Control", kSimpleCacheProbability);
      trial->group();
    }
#endif
  }
}

void ChromeBrowserFieldTrials::SetUpCacheSensitivityAnalysisFieldTrial() {
  const base::FieldTrial::Probability kDivisor = 100;

  base::FieldTrial::Probability sensitivity_analysis_probability = 0;

#if defined(OS_ANDROID)
  switch (chrome::VersionInfo::GetChannel()) {
    case chrome::VersionInfo::CHANNEL_DEV:
      sensitivity_analysis_probability = 10;
      break;
    case chrome::VersionInfo::CHANNEL_BETA:
      sensitivity_analysis_probability = 5;
      break;
    case chrome::VersionInfo::CHANNEL_STABLE:
      sensitivity_analysis_probability = 1;
      break;
    default:
      break;
  }
#endif

  scoped_refptr<base::FieldTrial> trial(
      base::FieldTrialList::FactoryGetFieldTrial("CacheSensitivityAnalysis",
                                                 kDivisor, "No",
                                                 2013, 06, 15, NULL));
  trial->AppendGroup("ControlA", sensitivity_analysis_probability);
  trial->AppendGroup("ControlB", sensitivity_analysis_probability);
  trial->AppendGroup("100A", sensitivity_analysis_probability);
  trial->AppendGroup("100B", sensitivity_analysis_probability);
  trial->AppendGroup("200A", sensitivity_analysis_probability);
  trial->AppendGroup("200B", sensitivity_analysis_probability);
  // TODO(gavinp,rvargas): Re-add 400 group to field trial if results justify.
}

void ChromeBrowserFieldTrials::WindowsOverlappedTCPReadsFieldTrial() {
#if defined(OS_WIN)
  if (parsed_command_line_.HasSwitch(switches::kOverlappedRead)) {
    std::string option =
        parsed_command_line_.GetSwitchValueASCII(switches::kOverlappedRead);
    if (LowerCaseEqualsASCII(option, "off"))
      net::TCPClientSocketWin::DisableOverlappedReads();
  } else {
    const base::FieldTrial::Probability kDivisor = 2;  // 1 in 2 chance
    const base::FieldTrial::Probability kOverlappedReadProbability = 1;
    scoped_refptr<base::FieldTrial> overlapped_reads_trial(
        base::FieldTrialList::FactoryGetFieldTrial("OverlappedReadImpact",
            kDivisor, "OverlappedReadEnabled", 2013, 6, 1, NULL));
    int overlapped_reads_disabled_group =
        overlapped_reads_trial->AppendGroup("OverlappedReadDisabled",
                                            kOverlappedReadProbability);
    int assigned_group = overlapped_reads_trial->group();
    if (assigned_group == overlapped_reads_disabled_group)
      net::TCPClientSocketWin::DisableOverlappedReads();
  }
#endif
}

void ChromeBrowserFieldTrials::InstantiateDynamicTrials() {
  // Call |FindValue()| on the trials below, which may come from the server, to
  // ensure they get marked as "used" for the purposes of data reporting.
  base::FieldTrialList::FindValue("UMA-Dynamic-Binary-Uniformity-Trial");
  base::FieldTrialList::FindValue("UMA-Dynamic-Uniformity-Trial");
  base::FieldTrialList::FindValue("InstantDummy");
  base::FieldTrialList::FindValue("InstantChannel");
  base::FieldTrialList::FindValue("Test0PercentDefault");
  // Activate the autocomplete dynamic field trials.
  OmniboxFieldTrial::ActivateDynamicTrials();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/policy/device_token_fetcher.h"

#include <algorithm>

#include "base/message_loop.h"
#include "chrome/browser/policy/cloud_policy_cache.h"
#include "chrome/browser/policy/device_management_service.h"
#include "chrome/browser/policy/proto/device_management_constants.h"
#include "chrome/browser/policy/proto/device_management_local.pb.h"

namespace {

// Retry after 3 seconds (with exponential backoff) after token fetch errors.
const int64 kTokenFetchErrorDelayMilliseconds = 3 * 1000;
// For unmanaged devices, check once per day whether they're still unmanaged.
const int64 kUnmanagedDeviceRefreshRateMilliseconds = 24 * 60 * 60 * 1000;

}  // namespace

namespace policy {

namespace em = enterprise_management;

DeviceTokenFetcher::DeviceTokenFetcher(
    DeviceManagementService* service,
    CloudPolicyCache* cache)
    : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  Initialize(service,
             cache,
             kTokenFetchErrorDelayMilliseconds,
             kUnmanagedDeviceRefreshRateMilliseconds);
}

DeviceTokenFetcher::DeviceTokenFetcher(
    DeviceManagementService* service,
    CloudPolicyCache* cache,
    int64 token_fetch_error_delay_ms,
    int64 unmanaged_device_refresh_rate_ms)
    : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  Initialize(service,
             cache,
             token_fetch_error_delay_ms,
             unmanaged_device_refresh_rate_ms);
}

DeviceTokenFetcher::~DeviceTokenFetcher() {
  CancelRetryTask();
}

void DeviceTokenFetcher::FetchToken(
    const std::string& auth_token,
    const std::string& device_id,
    em::DeviceRegisterRequest_Type policy_type,
    const std::string& machine_id) {
  SetState(STATE_INACTIVE);
  auth_token_ = auth_token;
  device_id_ = device_id;
  policy_type_ = policy_type;
  machine_id_ = machine_id;
  FetchTokenInternal();
}

void DeviceTokenFetcher::FetchTokenInternal() {
  DCHECK(state_ != STATE_TOKEN_AVAILABLE);
  DCHECK(!auth_token_.empty() && !device_id_.empty());
  // Construct a new backend, which will discard any previous requests.
  backend_.reset(service_->CreateBackend());
  em::DeviceRegisterRequest request;
  request.set_type(policy_type_);
  if (!machine_id_.empty())
    request.set_machine_id(machine_id_);
  request.set_machine_model(kRegisterRequestMachineModel);
  backend_->ProcessRegisterRequest(auth_token_, device_id_, request, this);
}

const std::string& DeviceTokenFetcher::GetDeviceToken() {
  return device_token_;
}

void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) {
  observer_list_.AddObserver(observer);
}

void DeviceTokenFetcher::RemoveObserver(
    DeviceTokenFetcher::Observer* observer) {
  observer_list_.RemoveObserver(observer);
}

void DeviceTokenFetcher::HandleRegisterResponse(
    const em::DeviceRegisterResponse& response) {
  if (response.has_device_management_token()) {
    device_token_ = response.device_management_token();
    SetState(STATE_TOKEN_AVAILABLE);
  } else {
    NOTREACHED();
    SetState(STATE_ERROR);
  }
}

void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
  if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) {
    cache_->SetUnmanaged();
    SetState(STATE_UNMANAGED);
  }
  SetState(STATE_ERROR);
}

void DeviceTokenFetcher::Initialize(DeviceManagementService* service,
                                    CloudPolicyCache* cache,
                                    int64 token_fetch_error_delay_ms,
                                    int64 unmanaged_device_refresh_rate_ms) {
  service_ = service;
  cache_ = cache;
  token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
  effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
  unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms;
  state_ = STATE_INACTIVE;
  retry_task_ = NULL;

  if (cache_->is_unmanaged())
    SetState(STATE_UNMANAGED);
}

void DeviceTokenFetcher::SetState(FetcherState state) {
  state_ = state;
  if (state_ != STATE_ERROR)
    effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_;

  base::Time delayed_work_at;
  switch (state_) {
    case STATE_INACTIVE:
      device_token_.clear();
      auth_token_.clear();
      device_id_.clear();
      break;
    case STATE_TOKEN_AVAILABLE:
      FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceTokenAvailable());
      break;
    case STATE_UNMANAGED:
      delayed_work_at = cache_->last_policy_refresh_time() +
          base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_);
      break;
    case STATE_ERROR:
      delayed_work_at = base::Time::Now() +
          base::TimeDelta::FromMilliseconds(
              effective_token_fetch_error_delay_ms_);
      effective_token_fetch_error_delay_ms_ *= 2;
      break;
  }

  CancelRetryTask();
  if (!delayed_work_at.is_null()) {
    base::Time now(base::Time::Now());
    int64 delay = std::max<int64>((delayed_work_at - now).InMilliseconds(), 0);
    retry_task_ = method_factory_.NewRunnableMethod(
            &DeviceTokenFetcher::ExecuteRetryTask);
    MessageLoop::current()->PostDelayedTask(FROM_HERE, retry_task_,
                                            delay);
  }
}

void DeviceTokenFetcher::ExecuteRetryTask() {
  DCHECK(retry_task_);
  retry_task_ = NULL;

  switch (state_) {
    case STATE_INACTIVE:
    case STATE_TOKEN_AVAILABLE:
      break;
    case STATE_UNMANAGED:
    case STATE_ERROR:
      FetchTokenInternal();
      break;
  }
}

void DeviceTokenFetcher::CancelRetryTask() {
  if (retry_task_) {
    retry_task_->Cancel();
    retry_task_ = NULL;
  }
}

}  // namespace policy
<commit_msg>Fix crash caused by DCHECK for unmanaged ChromeOS devices.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/policy/device_token_fetcher.h"

#include <algorithm>

#include "base/message_loop.h"
#include "chrome/browser/policy/cloud_policy_cache.h"
#include "chrome/browser/policy/device_management_service.h"
#include "chrome/browser/policy/proto/device_management_constants.h"
#include "chrome/browser/policy/proto/device_management_local.pb.h"

namespace {

// Retry after 3 seconds (with exponential backoff) after token fetch errors.
const int64 kTokenFetchErrorDelayMilliseconds = 3 * 1000;
// For unmanaged devices, check once per day whether they're still unmanaged.
const int64 kUnmanagedDeviceRefreshRateMilliseconds = 24 * 60 * 60 * 1000;

}  // namespace

namespace policy {

namespace em = enterprise_management;

DeviceTokenFetcher::DeviceTokenFetcher(
    DeviceManagementService* service,
    CloudPolicyCache* cache)
    : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  Initialize(service,
             cache,
             kTokenFetchErrorDelayMilliseconds,
             kUnmanagedDeviceRefreshRateMilliseconds);
}

DeviceTokenFetcher::DeviceTokenFetcher(
    DeviceManagementService* service,
    CloudPolicyCache* cache,
    int64 token_fetch_error_delay_ms,
    int64 unmanaged_device_refresh_rate_ms)
    : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  Initialize(service,
             cache,
             token_fetch_error_delay_ms,
             unmanaged_device_refresh_rate_ms);
}

DeviceTokenFetcher::~DeviceTokenFetcher() {
  CancelRetryTask();
}

void DeviceTokenFetcher::FetchToken(
    const std::string& auth_token,
    const std::string& device_id,
    em::DeviceRegisterRequest_Type policy_type,
    const std::string& machine_id) {
  SetState(STATE_INACTIVE);
  auth_token_ = auth_token;
  device_id_ = device_id;
  policy_type_ = policy_type;
  machine_id_ = machine_id;
  FetchTokenInternal();
}

void DeviceTokenFetcher::FetchTokenInternal() {
  DCHECK(state_ != STATE_TOKEN_AVAILABLE);
  if (auth_token_.empty() || device_id_.empty()) {
    // Maybe this device is unmanaged, just exit. The CloudPolicyController
    // will call FetchToken() again if something changes.
    return;
  }
  // Construct a new backend, which will discard any previous requests.
  backend_.reset(service_->CreateBackend());
  em::DeviceRegisterRequest request;
  request.set_type(policy_type_);
  if (!machine_id_.empty())
    request.set_machine_id(machine_id_);
  request.set_machine_model(kRegisterRequestMachineModel);
  backend_->ProcessRegisterRequest(auth_token_, device_id_, request, this);
}

const std::string& DeviceTokenFetcher::GetDeviceToken() {
  return device_token_;
}

void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) {
  observer_list_.AddObserver(observer);
}

void DeviceTokenFetcher::RemoveObserver(
    DeviceTokenFetcher::Observer* observer) {
  observer_list_.RemoveObserver(observer);
}

void DeviceTokenFetcher::HandleRegisterResponse(
    const em::DeviceRegisterResponse& response) {
  if (response.has_device_management_token()) {
    device_token_ = response.device_management_token();
    SetState(STATE_TOKEN_AVAILABLE);
  } else {
    NOTREACHED();
    SetState(STATE_ERROR);
  }
}

void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
  if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) {
    cache_->SetUnmanaged();
    SetState(STATE_UNMANAGED);
  }
  SetState(STATE_ERROR);
}

void DeviceTokenFetcher::Initialize(DeviceManagementService* service,
                                    CloudPolicyCache* cache,
                                    int64 token_fetch_error_delay_ms,
                                    int64 unmanaged_device_refresh_rate_ms) {
  service_ = service;
  cache_ = cache;
  token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
  effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
  unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms;
  state_ = STATE_INACTIVE;
  retry_task_ = NULL;

  if (cache_->is_unmanaged())
    SetState(STATE_UNMANAGED);
}

void DeviceTokenFetcher::SetState(FetcherState state) {
  state_ = state;
  if (state_ != STATE_ERROR)
    effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_;

  base::Time delayed_work_at;
  switch (state_) {
    case STATE_INACTIVE:
      device_token_.clear();
      auth_token_.clear();
      device_id_.clear();
      break;
    case STATE_TOKEN_AVAILABLE:
      FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceTokenAvailable());
      break;
    case STATE_UNMANAGED:
      delayed_work_at = cache_->last_policy_refresh_time() +
          base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_);
      break;
    case STATE_ERROR:
      delayed_work_at = base::Time::Now() +
          base::TimeDelta::FromMilliseconds(
              effective_token_fetch_error_delay_ms_);
      effective_token_fetch_error_delay_ms_ *= 2;
      break;
  }

  CancelRetryTask();
  if (!delayed_work_at.is_null()) {
    base::Time now(base::Time::Now());
    int64 delay = std::max<int64>((delayed_work_at - now).InMilliseconds(), 0);
    retry_task_ = method_factory_.NewRunnableMethod(
            &DeviceTokenFetcher::ExecuteRetryTask);
    MessageLoop::current()->PostDelayedTask(FROM_HERE, retry_task_,
                                            delay);
  }
}

void DeviceTokenFetcher::ExecuteRetryTask() {
  DCHECK(retry_task_);
  retry_task_ = NULL;

  switch (state_) {
    case STATE_INACTIVE:
    case STATE_TOKEN_AVAILABLE:
      break;
    case STATE_UNMANAGED:
    case STATE_ERROR:
      FetchTokenInternal();
      break;
  }
}

void DeviceTokenFetcher::CancelRetryTask() {
  if (retry_task_) {
    retry_task_->Cancel();
    retry_task_ = NULL;
  }
}

}  // namespace policy
<|endoftext|>