<commit_before>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "ContextSearchBm.h"
#include "Benchmark.h"
#include <unordered_map>

Benchmark ContextSearchBm::Search(void) {
  static const size_t n = 10000;

  // Prime object insertion, a few tests require this
  AutoRequired<Foo>();

  return{
    {
      "std::unordered_map::operator[]",
      [](Stopwatch& sw) {
        std::unordered_map<int, int> ref;
        ref[0] = 212;
        ref[1] = 21;

        sw.Start();
        for (size_t i = n; i--;)
          ref[i % 2];
        sw.Stop(n);
      }
    },
    {
      "Autowired<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (size_t i = n; i--;)
          Autowired<Foo>();
        sw.Stop(n);
      }
    },
    {
      "AutowiredFast<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (size_t i = n; i--;)
          AutowiredFast<Foo>();
        sw.Stop(n);
      }
    }
  };
}

template<int N>
struct dummy:
  public ContextMember
{};

void InjectDummy(void) {
  Autowired<dummy<1>>();
  Autowired<dummy<2>>();
  Autowired<dummy<3>>();
  Autowired<dummy<4>>();
  Autowired<dummy<5>>();
  Autowired<dummy<6>>();
  Autowired<dummy<7>>();
  Autowired<dummy<8>>();
  Autowired<dummy<9>>();
  Autowired<dummy<10>>();
  Autowired<dummy<11>>();
  Autowired<dummy<12>>();
  Autowired<dummy<13>>();
  Autowired<dummy<14>>();
  Autowired<dummy<15>>();
  Autowired<dummy<16>>();
  Autowired<dummy<17>>();
  Autowired<dummy<18>>();
  Autowired<dummy<19>>();
  Autowired<dummy<20>>();
  Autowired<dummy<21>>();
  Autowired<dummy<22>>();
  Autowired<dummy<23>>();
  Autowired<dummy<24>>();
  Autowired<dummy<25>>();
};

Benchmark ContextSearchBm::Cache(void)
{
  std::chrono::nanoseconds baseline(0);
  std::chrono::nanoseconds benchmark(0);
  static const size_t n = 100;

  return Benchmark{
    {
      "Inject+Miss",
      [] (Stopwatch& sw) {
        std::vector<std::shared_ptr<CoreContext>> ctxts(n);
        for (size_t i = 0; i < n; i++)
          ctxts[i] = AutoCreateContext();

        sw.Start();
        for(auto& ctxt : ctxts) {
          CurrentContextPusher pshr(ctxt);
          InjectDummy();
        }
        sw.Stop(25 * n);
      }
    },
    {
      "Inject",
      [] (Stopwatch& sw) {
        std::vector<std::shared_ptr<CoreContext>> ctxts(n);
        for (size_t i = 0; i < n; i++) {
          ctxts[i] = AutoCreateContext();
          CurrentContextPusher pshr(ctxts[i]);
          InjectDummy();
        }

        sw.Start();
        for (size_t i = n; i--;) {
          CurrentContextPusher pshr(ctxts[i]);
          InjectDummy();
        }
        sw.Stop(25 * n);
      }
    }
  };
}

Benchmark ContextSearchBm::Fast(void) {
  // All of these tests will operate in the same context:
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  static const size_t n = 500;

  // Prime all memos:
  InjectDummy();

  return Benchmark{
    {
      "Autowired<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (int i = 0; i < n; ++i)
          InjectDummy();
        sw.Stop(n * 25);
      }
    },
    {
      "AutowiredFast<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (int i = 0; i < n; ++i) {
          AutowiredFast<dummy<1>> a1;
          AutowiredFast<dummy<2>>();
          AutowiredFast<dummy<3>>();
          AutowiredFast<dummy<4>>();
          AutowiredFast<dummy<5>>();
          AutowiredFast<dummy<6>>();
          AutowiredFast<dummy<7>>();
          AutowiredFast<dummy<8>>();
          AutowiredFast<dummy<9>>();
          AutowiredFast<dummy<10>>();
          AutowiredFast<dummy<11>>();
          AutowiredFast<dummy<12>>();
          AutowiredFast<dummy<13>>();
          AutowiredFast<dummy<14>>();
          AutowiredFast<dummy<15>>();
          AutowiredFast<dummy<16>>();
          AutowiredFast<dummy<17>>();
          AutowiredFast<dummy<18>>();
          AutowiredFast<dummy<19>>();
          AutowiredFast<dummy<20>>();
          AutowiredFast<dummy<21>>();
          AutowiredFast<dummy<22>>();
          AutowiredFast<dummy<23>>();
          AutowiredFast<dummy<24>>();
          AutowiredFast<dummy<25>>();
        }
        sw.Stop(n * 25);
      }
    }
  };
}
<commit_msg>Add a baseline for the "fast" benchmark<commit_after>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "ContextSearchBm.h"
#include "Benchmark.h"
#include <algorithm>
#include <unordered_map>

Benchmark ContextSearchBm::Search(void) {
  static const size_t n = 10000;

  // Prime object insertion, a few tests require this
  AutoRequired<Foo>();

  return{
    {
      "std::unordered_map::operator[]",
      [](Stopwatch& sw) {
        std::unordered_map<int, int> ref;
        ref[0] = 212;
        ref[1] = 21;

        sw.Start();
        for (size_t i = n; i--;)
          ref[i % 2];
        sw.Stop(n);
      }
    },
    {
      "Autowired<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (size_t i = n; i--;)
          Autowired<Foo>();
        sw.Stop(n);
      }
    },
    {
      "AutowiredFast<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (size_t i = n; i--;)
          AutowiredFast<Foo>();
        sw.Stop(n);
      }
    }
  };
}

template<int N>
struct dummy:
  public ContextMember
{};

void InjectDummy(void) {
  Autowired<dummy<1>>();
  Autowired<dummy<2>>();
  Autowired<dummy<3>>();
  Autowired<dummy<4>>();
  Autowired<dummy<5>>();
  Autowired<dummy<6>>();
  Autowired<dummy<7>>();
  Autowired<dummy<8>>();
  Autowired<dummy<9>>();
  Autowired<dummy<10>>();
  Autowired<dummy<11>>();
  Autowired<dummy<12>>();
  Autowired<dummy<13>>();
  Autowired<dummy<14>>();
  Autowired<dummy<15>>();
  Autowired<dummy<16>>();
  Autowired<dummy<17>>();
  Autowired<dummy<18>>();
  Autowired<dummy<19>>();
  Autowired<dummy<20>>();
  Autowired<dummy<21>>();
  Autowired<dummy<22>>();
  Autowired<dummy<23>>();
  Autowired<dummy<24>>();
  Autowired<dummy<25>>();
};

Benchmark ContextSearchBm::Cache(void)
{
  std::chrono::nanoseconds baseline(0);
  std::chrono::nanoseconds benchmark(0);
  static const size_t n = 100;

  return Benchmark{
    {
      "Inject+Miss",
      [] (Stopwatch& sw) {
        std::vector<std::shared_ptr<CoreContext>> ctxts(n);
        for (size_t i = 0; i < n; i++)
          ctxts[i] = AutoCreateContext();

        sw.Start();
        for(auto& ctxt : ctxts) {
          CurrentContextPusher pshr(ctxt);
          InjectDummy();
        }
        sw.Stop(25 * n);
      }
    },
    {
      "Inject",
      [] (Stopwatch& sw) {
        std::vector<std::shared_ptr<CoreContext>> ctxts(n);
        for (size_t i = 0; i < n; i++) {
          ctxts[i] = AutoCreateContext();
          CurrentContextPusher pshr(ctxts[i]);
          InjectDummy();
        }

        sw.Start();
        for (size_t i = n; i--;) {
          CurrentContextPusher pshr(ctxts[i]);
          InjectDummy();
        }
        sw.Stop(25 * n);
      }
    }
  };
}

Benchmark ContextSearchBm::Fast(void) {
  // All of these tests will operate in the same context:
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  static const size_t n = 500;

  // Prime all memos:
  InjectDummy();

  return Benchmark{
    {
      "unordered_map<typeinfo, shared_ptr>",
      [](Stopwatch& sw) {
        static const std::type_info* tis [] = {
          &typeid(dummy<1>),
          &typeid(dummy<2>),
          &typeid(dummy<3>),
          &typeid(dummy<4>),
          &typeid(dummy<5>),
          &typeid(dummy<6>),
          &typeid(dummy<7>),
          &typeid(dummy<8>),
          &typeid(dummy<9>),
          &typeid(dummy<10>),
          &typeid(dummy<11>),
          &typeid(dummy<12>),
          &typeid(dummy<13>),
          &typeid(dummy<14>),
          &typeid(dummy<15>),
          &typeid(dummy<16>),
          &typeid(dummy<17>),
          &typeid(dummy<18>),
          &typeid(dummy<19>),
          &typeid(dummy<20>),
          &typeid(dummy<21>),
          &typeid(dummy<22>),
          &typeid(dummy<23>),
          &typeid(dummy<24>),
          &typeid(dummy<25>)
        };

        std::unordered_map<std::type_index, std::shared_ptr<bool>> v;
        for (const auto* ti : tis)
          v[*ti] = std::make_shared<bool>(true);

        sw.Start();
        for (int i = 0; i < n; ++i) {
          v.find(*tis[i % 25]);
        }
        sw.Stop(n);
      }
    },
    {
      "Autowired<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (int i = 0; i < n; ++i)
          InjectDummy();
        sw.Stop(n * 25);
      }
    },
    {
      "AutowiredFast<T>",
      [](Stopwatch& sw) {
        sw.Start();
        for (int i = 0; i < n; ++i) {
          AutowiredFast<dummy<1>>();
          AutowiredFast<dummy<2>>();
          AutowiredFast<dummy<3>>();
          AutowiredFast<dummy<4>>();
          AutowiredFast<dummy<5>>();
          AutowiredFast<dummy<6>>();
          AutowiredFast<dummy<7>>();
          AutowiredFast<dummy<8>>();
          AutowiredFast<dummy<9>>();
          AutowiredFast<dummy<10>>();
          AutowiredFast<dummy<11>>();
          AutowiredFast<dummy<12>>();
          AutowiredFast<dummy<13>>();
          AutowiredFast<dummy<14>>();
          AutowiredFast<dummy<15>>();
          AutowiredFast<dummy<16>>();
          AutowiredFast<dummy<17>>();
          AutowiredFast<dummy<18>>();
          AutowiredFast<dummy<19>>();
          AutowiredFast<dummy<20>>();
          AutowiredFast<dummy<21>>();
          AutowiredFast<dummy<22>>();
          AutowiredFast<dummy<23>>();
          AutowiredFast<dummy<24>>();
          AutowiredFast<dummy<25>>();
        }
        sw.Stop(n * 25);
      }
    }
  };
}
<|endoftext|>


<commit_before>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "TestFixtures/Decoration.hpp"
#include <autowiring/autowiring.h>
#include <autowiring/AutoSelfUpdate.h>
#include <autowiring/auto_prev.h>

class AutoFilterSequencing:
  public testing::Test
{
public:
  AutoFilterSequencing(void) {
    AutoCurrentContext()->Initiate();
  }
};

class FilterFirst {
public:
  FilterFirst(void) :
    m_magic(0xDEADBEEF),
    m_called(0)
  {}

  const int m_magic;
  int m_called;

  void AutoFilter(AutoPacket& pkt) {
    ASSERT_EQ(0xDEADBEEF, m_magic) << "Magic value was corrupted, pointer was not adjusted to the correct offset";
    ++m_called;
    pkt.Decorate(Decoration<0>());
  }
};

class FilterFirstValidateInheritance:
  public FilterFirst
{};

static_assert(
  std::is_same<
  FilterFirst,
  Decompose<decltype(&FilterFirstValidateInheritance::AutoFilter)>::type
  >::value,
  "Decomposed type did not correctly name the implementing type of an inherited method"
  );

TEST_F(AutoFilterSequencing, VerifyFirstLastCalls) {
  AutoRequired<AutoPacketFactory> factory;
  AutoRequired<FilterFirst> first;

  {
    auto pkt = factory->NewPacket();
    ASSERT_EQ(1, first->m_called) << "First-call filter was not applied";
  }
  ASSERT_EQ(1, first->m_called) << "First-call filter was applied as final call";
}

class FilterOutDeferred:
  public CoreThread
{
public:
  Deferred AutoFilter(auto_out<Decoration<0>> out) {
    //Default constructor sets i == 0
    return Deferred(this);
  }
};

TEST_F(AutoFilterSequencing, SuccessorAliasRules) {
  AutoRequired<AutoPacketFactory> factory;
  auto packet1 = factory->NewPacket();
  auto packet2 = packet1->Successor();
  ASSERT_TRUE(!!packet2) << "Returned successor packet was null";

  auto expected = factory->NewPacket();

  ASSERT_EQ(expected, packet2) << "Expected that the successor packet would match the next packet returned by the factory";
}

TEST_F(AutoFilterSequencing, SuccessorHoldViolationCheck) {
  AutoRequired<AutoPacketFactory> factory;
  auto packet1 = factory->NewPacket();
  auto packet2 = packet1->Successor();

  ASSERT_TRUE(packet1.unique()) << "Expected that the first issued packet shared pointer not to be aliased anywhere";

  packet1.reset();
  factory->NewPacket();

  ASSERT_TRUE(packet2.unique()) << "Expected that a successor packet would be unique when the principal was destroyed";
}

TEST_F(AutoFilterSequencing, PacketReverseSuccessor) {
  AutoRequired<AutoPacketFactory> factory;

  auto packet1 = factory->NewPacket();
  auto packet2 = factory->NewPacket();

  ASSERT_EQ(packet2, packet1->Successor()) << "Successor packet obtained after generation from the factory did not match as expected";
}

TEST_F(AutoFilterSequencing, ManySuccessors) {
  AutoRequired<AutoPacketFactory> factory;
  {
    auto packetA = factory->NewPacket();
    auto packet5 = packetA->Successor()->Successor()->Successor()->Successor();

    factory->NewPacket();
    factory->NewPacket();
    factory->NewPacket();
    auto packetE = factory->NewPacket();

    ASSERT_EQ(packet5, packetE) << "Successor packet obtained after generation from the factory did not match as expected";
  }

  AutoRequired<FilterFirst> first;
  {
    auto packetA = factory->NewPacket();
    packetA->Successor()->Successor()->Successor()->Successor();
    ASSERT_EQ(1, first->m_called) << "AutoFilter triggered from successor";

    factory->NewPacket();
    ASSERT_EQ(2, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(3, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(4, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(5, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(6, first->m_called) << "AutoFilter not triggered from new packet";
  }
}

class PrevFilter {
public:
  PrevFilter(void):
    m_called(0)
  {}

  int prev_value;
  int m_called;

  void AutoFilter(int current, auto_prev<int> prev) {
    ++m_called;
    if (prev) {
      EXPECT_EQ(prev_value, *prev) << "auto_prev isn't set to the previous value";
    }
    prev_value = current;
  }
};

TEST_F(AutoFilterSequencing, SimplePrev) {
  AutoRequired<AutoPacketFactory> factory;
  AutoRequired<PrevFilter> filter;

  for (int i=0; i<10; ++i) {
    auto packet = factory->NewPacket();
    packet->Decorate(i);
  }

  ASSERT_EQ(10, filter->m_called) << "AutoFilter not called";
}
<commit_msg>Make auto_prev test robust to empty auto_prev values<commit_after>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "TestFixtures/Decoration.hpp"
#include <autowiring/autowiring.h>
#include <autowiring/AutoSelfUpdate.h>
#include <autowiring/auto_prev.h>

class AutoFilterSequencing:
  public testing::Test
{
public:
  AutoFilterSequencing(void) {
    AutoCurrentContext()->Initiate();
  }
};

class FilterFirst {
public:
  FilterFirst(void) :
    m_magic(0xDEADBEEF),
    m_called(0)
  {}

  const int m_magic;
  int m_called;

  void AutoFilter(AutoPacket& pkt) {
    ASSERT_EQ(0xDEADBEEF, m_magic) << "Magic value was corrupted, pointer was not adjusted to the correct offset";
    ++m_called;
    pkt.Decorate(Decoration<0>());
  }
};

class FilterFirstValidateInheritance:
  public FilterFirst
{};

static_assert(
  std::is_same<
  FilterFirst,
  Decompose<decltype(&FilterFirstValidateInheritance::AutoFilter)>::type
  >::value,
  "Decomposed type did not correctly name the implementing type of an inherited method"
  );

TEST_F(AutoFilterSequencing, VerifyFirstLastCalls) {
  AutoRequired<AutoPacketFactory> factory;
  AutoRequired<FilterFirst> first;

  {
    auto pkt = factory->NewPacket();
    ASSERT_EQ(1, first->m_called) << "First-call filter was not applied";
  }
  ASSERT_EQ(1, first->m_called) << "First-call filter was applied as final call";
}

class FilterOutDeferred:
  public CoreThread
{
public:
  Deferred AutoFilter(auto_out<Decoration<0>> out) {
    //Default constructor sets i == 0
    return Deferred(this);
  }
};

TEST_F(AutoFilterSequencing, SuccessorAliasRules) {
  AutoRequired<AutoPacketFactory> factory;
  auto packet1 = factory->NewPacket();
  auto packet2 = packet1->Successor();
  ASSERT_TRUE(!!packet2) << "Returned successor packet was null";

  auto expected = factory->NewPacket();

  ASSERT_EQ(expected, packet2) << "Expected that the successor packet would match the next packet returned by the factory";
}

TEST_F(AutoFilterSequencing, SuccessorHoldViolationCheck) {
  AutoRequired<AutoPacketFactory> factory;
  auto packet1 = factory->NewPacket();
  auto packet2 = packet1->Successor();

  ASSERT_TRUE(packet1.unique()) << "Expected that the first issued packet shared pointer not to be aliased anywhere";

  packet1.reset();
  factory->NewPacket();

  ASSERT_TRUE(packet2.unique()) << "Expected that a successor packet would be unique when the principal was destroyed";
}

TEST_F(AutoFilterSequencing, PacketReverseSuccessor) {
  AutoRequired<AutoPacketFactory> factory;

  auto packet1 = factory->NewPacket();
  auto packet2 = factory->NewPacket();

  ASSERT_EQ(packet2, packet1->Successor()) << "Successor packet obtained after generation from the factory did not match as expected";
}

TEST_F(AutoFilterSequencing, ManySuccessors) {
  AutoRequired<AutoPacketFactory> factory;
  {
    auto packetA = factory->NewPacket();
    auto packet5 = packetA->Successor()->Successor()->Successor()->Successor();

    factory->NewPacket();
    factory->NewPacket();
    factory->NewPacket();
    auto packetE = factory->NewPacket();

    ASSERT_EQ(packet5, packetE) << "Successor packet obtained after generation from the factory did not match as expected";
  }

  AutoRequired<FilterFirst> first;
  {
    auto packetA = factory->NewPacket();
    packetA->Successor()->Successor()->Successor()->Successor();
    ASSERT_EQ(1, first->m_called) << "AutoFilter triggered from successor";

    factory->NewPacket();
    ASSERT_EQ(2, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(3, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(4, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(5, first->m_called) << "AutoFilter not triggered from new packet";
    factory->NewPacket();
    ASSERT_EQ(6, first->m_called) << "AutoFilter not triggered from new packet";
  }
}

class PrevFilter {
public:
  PrevFilter(void):
    m_prev_value(-1),
    m_called(0),
    m_num_empty_prev(0)
  {}

  int m_prev_value;
  int m_called;
  int m_num_empty_prev;

  void AutoFilter(int current, auto_prev<int> prev) {
    ++m_called;
    if (prev) {
      EXPECT_EQ(m_prev_value, *prev) << "auto_prev isn't set to the previous value";
      m_num_empty_prev++;
    }
    m_prev_value = current;
  }
};

TEST_F(AutoFilterSequencing, SimplePrev) {
  AutoRequired<AutoPacketFactory> factory;
  AutoRequired<PrevFilter> filter;

  for (int i=0; i<10; ++i) {
    auto packet = factory->NewPacket();
    packet->Decorate(i);
  }

  ASSERT_EQ(10, filter->m_called) << "AutoFilter not called";
  ASSERT_EQ(1, filter->m_num_empty_prev) << "Prev should only be null for the first call";
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "serializer.hh"
#include "database.hh"
#include "types.hh"
#include "utils/serialization.hh"

typedef uint32_t count_type; // Me thinks 32-bits are enough for "normal" count purposes.

template<>
db::serializer<utils::UUID>::serializer(const utils::UUID& uuid)
        : _item(uuid), _size(2 * sizeof(uint64_t)) {
}

template<>
void db::serializer<utils::UUID>::write(output& out,
        const type& t) {
    out.write(t.get_most_significant_bits());
    out.write(t.get_least_significant_bits());
}

template<>
void db::serializer<utils::UUID>::read(utils::UUID& uuid, input& in) {
    uuid = read(in);
}

template<>
void db::serializer<utils::UUID>::skip(input& in) {
    in.skip(2 * sizeof(uint64_t));
}

template<> utils::UUID db::serializer<utils::UUID>::read(input& in) {
    auto msb = in.read<uint64_t>();
    auto lsb = in.read<uint64_t>();
    return utils::UUID(msb, lsb);
}

template<>
db::serializer<bytes>::serializer(const bytes& b)
        : _item(b), _size(output::serialized_size(b)) {
}

template<>
void db::serializer<bytes>::write(output& out, const type& t) {
    out.write(t);
}

template<>
void db::serializer<bytes>::read(bytes& b, input& in) {
    b = in.read<bytes>();
}

template<>
void db::serializer<bytes>::skip(input& in) {
    in.read<bytes>(); // FIXME: Avoid reading
}

template<>
db::serializer<bytes_view>::serializer(const bytes_view& v)
        : _item(v), _size(output::serialized_size(v)) {
}

template<>
void db::serializer<bytes_view>::write(output& out, const type& t) {
    out.write(t);
}

template<>
void db::serializer<bytes_view>::read(bytes_view& v, input& in) {
    v = in.read<bytes_view>();
}

template<>
bytes_view db::serializer<bytes_view>::read(input& in) {
    return in.read<bytes_view>();
}

template<>
db::serializer<sstring>::serializer(const sstring& s)
        : _item(s), _size(output::serialized_size(s)) {
}

template<>
void db::serializer<sstring>::write(output& out, const type& t) {
    out.write(t);
}

template<>
void db::serializer<sstring>::read(sstring& s, input& in) {
    s = in.read<sstring>();
}

template<>
void db::serializer<sstring>::skip(input& in) {
    in.read<sstring>(); // FIXME: avoid reading
}

template<>
db::serializer<tombstone>::serializer(const tombstone& t)
        : _item(t), _size(sizeof(t.timestamp) + sizeof(decltype(t.deletion_time.time_since_epoch().count()))) {
}

template<>
void db::serializer<tombstone>::write(output& out, const type& t) {
    out.write(t.timestamp);
    out.write(t.deletion_time.time_since_epoch().count());
}

template<>
void db::serializer<tombstone>::read(tombstone& t, input& in) {
    t.timestamp = in.read<decltype(t.timestamp)>();
    auto deletion_time = in.read<decltype(t.deletion_time.time_since_epoch().count())>();
    t.deletion_time = gc_clock::time_point(gc_clock::duration(deletion_time));
}

template<>
db::serializer<atomic_cell_view>::serializer(const atomic_cell_view& c)
        : _item(c), _size(bytes_view_serializer(c.serialize()).size()) {
}

template<>
void db::serializer<atomic_cell_view>::write(output& out, const atomic_cell_view& t) {
    bytes_view_serializer::write(out, t.serialize());
}

template<>
void db::serializer<atomic_cell_view>::read(atomic_cell_view& c, input& in) {
    c = atomic_cell_view::from_bytes(bytes_view_serializer::read(in));
}

template<>
atomic_cell_view db::serializer<atomic_cell_view>::read(input& in) {
    return atomic_cell_view::from_bytes(bytes_view_serializer::read(in));
}

template<>
db::serializer<collection_mutation_view>::serializer(const collection_mutation_view& c)
        : _item(c), _size(bytes_view_serializer(c.serialize()).size()) {
}

template<>
void db::serializer<collection_mutation_view>::write(output& out, const collection_mutation_view& t) {
    bytes_view_serializer::write(out, t.serialize());
}

template<>
void db::serializer<collection_mutation_view>::read(collection_mutation_view& c, input& in) {
    c = collection_mutation_view::from_bytes(bytes_view_serializer::read(in));
}

template<>
db::serializer<db::replay_position>::serializer(const db::replay_position& rp)
        : _item(rp), _size(sizeof(uint64_t) * 2) {
}

template<>
void db::serializer<db::replay_position>::write(output& out, const db::replay_position& rp) {
    out.write<uint64_t>(rp.id);
    out.write<uint64_t>(rp.pos);
}

template<>
void db::serializer<db::replay_position>::read(db::replay_position& rp, input& in) {
    rp.id = in.read<uint64_t>();
    rp.pos = in.read<uint64_t>();
}

template class db::serializer<tombstone> ;
template class db::serializer<bytes> ;
template class db::serializer<bytes_view> ;
template class db::serializer<sstring> ;
template class db::serializer<atomic_cell_view> ;
template class db::serializer<collection_mutation_view> ;
template class db::serializer<utils::UUID> ;
template class db::serializer<db::replay_position> ;
<commit_msg>db/serializer: Fix db::serializer<replay_position> format<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "serializer.hh"
#include "database.hh"
#include "types.hh"
#include "utils/serialization.hh"

typedef uint32_t count_type; // Me thinks 32-bits are enough for "normal" count purposes.

template<>
db::serializer<utils::UUID>::serializer(const utils::UUID& uuid)
        : _item(uuid), _size(2 * sizeof(uint64_t)) {
}

template<>
void db::serializer<utils::UUID>::write(output& out,
        const type& t) {
    out.write(t.get_most_significant_bits());
    out.write(t.get_least_significant_bits());
}

template<>
void db::serializer<utils::UUID>::read(utils::UUID& uuid, input& in) {
    uuid = read(in);
}

template<>
void db::serializer<utils::UUID>::skip(input& in) {
    in.skip(2 * sizeof(uint64_t));
}

template<> utils::UUID db::serializer<utils::UUID>::read(input& in) {
    auto msb = in.read<uint64_t>();
    auto lsb = in.read<uint64_t>();
    return utils::UUID(msb, lsb);
}

template<>
db::serializer<bytes>::serializer(const bytes& b)
        : _item(b), _size(output::serialized_size(b)) {
}

template<>
void db::serializer<bytes>::write(output& out, const type& t) {
    out.write(t);
}

template<>
void db::serializer<bytes>::read(bytes& b, input& in) {
    b = in.read<bytes>();
}

template<>
void db::serializer<bytes>::skip(input& in) {
    in.read<bytes>(); // FIXME: Avoid reading
}

template<>
db::serializer<bytes_view>::serializer(const bytes_view& v)
        : _item(v), _size(output::serialized_size(v)) {
}

template<>
void db::serializer<bytes_view>::write(output& out, const type& t) {
    out.write(t);
}

template<>
void db::serializer<bytes_view>::read(bytes_view& v, input& in) {
    v = in.read<bytes_view>();
}

template<>
bytes_view db::serializer<bytes_view>::read(input& in) {
    return in.read<bytes_view>();
}

template<>
db::serializer<sstring>::serializer(const sstring& s)
        : _item(s), _size(output::serialized_size(s)) {
}

template<>
void db::serializer<sstring>::write(output& out, const type& t) {
    out.write(t);
}

template<>
void db::serializer<sstring>::read(sstring& s, input& in) {
    s = in.read<sstring>();
}

template<>
void db::serializer<sstring>::skip(input& in) {
    in.read<sstring>(); // FIXME: avoid reading
}

template<>
db::serializer<tombstone>::serializer(const tombstone& t)
        : _item(t), _size(sizeof(t.timestamp) + sizeof(decltype(t.deletion_time.time_since_epoch().count()))) {
}

template<>
void db::serializer<tombstone>::write(output& out, const type& t) {
    out.write(t.timestamp);
    out.write(t.deletion_time.time_since_epoch().count());
}

template<>
void db::serializer<tombstone>::read(tombstone& t, input& in) {
    t.timestamp = in.read<decltype(t.timestamp)>();
    auto deletion_time = in.read<decltype(t.deletion_time.time_since_epoch().count())>();
    t.deletion_time = gc_clock::time_point(gc_clock::duration(deletion_time));
}

template<>
db::serializer<atomic_cell_view>::serializer(const atomic_cell_view& c)
        : _item(c), _size(bytes_view_serializer(c.serialize()).size()) {
}

template<>
void db::serializer<atomic_cell_view>::write(output& out, const atomic_cell_view& t) {
    bytes_view_serializer::write(out, t.serialize());
}

template<>
void db::serializer<atomic_cell_view>::read(atomic_cell_view& c, input& in) {
    c = atomic_cell_view::from_bytes(bytes_view_serializer::read(in));
}

template<>
atomic_cell_view db::serializer<atomic_cell_view>::read(input& in) {
    return atomic_cell_view::from_bytes(bytes_view_serializer::read(in));
}

template<>
db::serializer<collection_mutation_view>::serializer(const collection_mutation_view& c)
        : _item(c), _size(bytes_view_serializer(c.serialize()).size()) {
}

template<>
void db::serializer<collection_mutation_view>::write(output& out, const collection_mutation_view& t) {
    bytes_view_serializer::write(out, t.serialize());
}

template<>
void db::serializer<collection_mutation_view>::read(collection_mutation_view& c, input& in) {
    c = collection_mutation_view::from_bytes(bytes_view_serializer::read(in));
}

// Modified to match sstable/origin serialization. And the actual data type.
// Note however, that afaict, noone uses this serializer now
// (see comment in system_keyspace::save_truncation_record)
// I.e. consider dropping this alltogether.
template<>
db::serializer<db::replay_position>::serializer(const db::replay_position& rp)
        : _item(rp), _size(sizeof(uint64_t) + sizeof(uint32_t)) {
}

template<>
void db::serializer<db::replay_position>::write(output& out, const db::replay_position& rp) {
    out.write<uint64_t>(rp.id);
    out.write<uint32_t>(rp.pos);
}

template<>
void db::serializer<db::replay_position>::read(db::replay_position& rp, input& in) {
    rp.id = in.read<uint64_t>();
    rp.pos = in.read<uint32_t>();
}

template class db::serializer<tombstone> ;
template class db::serializer<bytes> ;
template class db::serializer<bytes_view> ;
template class db::serializer<sstring> ;
template class db::serializer<atomic_cell_view> ;
template class db::serializer<collection_mutation_view> ;
template class db::serializer<utils::UUID> ;
template class db::serializer<db::replay_position> ;
<|endoftext|>


<commit_before>#pragma once
#include "atom.h"

namespace Nany
{

	inline Atom* Atom::parentScope()
	{
		return (!scopeForNameResolution) ? parent : scopeForNameResolution;
	}

	inline const Atom* Atom::parentScope() const
	{
		return (!scopeForNameResolution) ? parent : scopeForNameResolution;
	}

	inline AnyString Atom::name() const
	{
		return m_name;
	}

	inline bool Atom::canCaptureVariabes() const
	{
		return flags.has(Flags::captureVariables)
			or (isClassMember() and parent->flags.has(Flags::captureVariables));
	}

	inline Atom* Atom::createDummy()
	{
		return new Atom("", Type::classdef);
	}

	inline CLID Atom::clid() const
	{
		return CLID::AtomMapID(atomid);
	}

	inline bool Atom::isNamespace() const
	{
		return type == Type::namespacedef;
	}

	inline bool Atom::isClass() const
	{
		return type == Type::classdef;
	}

	inline bool Atom::isAnonymousClass() const
	{
		return type == Type::classdef and m_name.empty();
	}

	inline bool Atom::isCtor() const
	{
		return category(Category::ctor);
	}

	inline bool Atom::isDtor() const
	{
		return category(Category::dtor);
	}

	inline bool Atom::isCloneCtor() const
	{
		return category(Category::clone);
	}

	inline bool Atom::isUnit() const
	{
		return type == Type::unit;
	}

	inline bool Atom::isTypeAlias() const
	{
		return type == Type::typealias;
	}

	inline bool Atom::isFunction() const
	{
		return type == Type::funcdef;
	}

	inline bool Atom::isOperator() const
	{
		return category(Category::funcoperator);
	}

	inline bool Atom::isSpecial() const
	{
		return category(Category::special);
	}

	inline bool Atom::isView() const
	{
		return category(Category::view);
	}

	inline bool Atom::isFunctor() const
	{
		return category(Category::functor);
	}

	inline bool Atom::isCapturedVariable() const
	{
		return category(Category::capturedVar);
	}

	inline bool Atom::isMemberVarDefaultInit() const
	{
		return category(Category::defvarInit);
	}

	inline bool Atom::isMemberVariable() const
	{
		return (type == Type::vardef) and category(Category::classParent);
	}

	inline bool Atom::isClassMember() const
	{
		return (type != Type::classdef) and category(Category::classParent);
	}

	inline bool Atom::isPropertyGet() const
	{
		return category(Category::propget);
	}

	inline bool Atom::isPropertySet() const
	{
		return category(Category::propset);
	}

	inline bool Atom::isPropertySetCustom() const
	{
		return category(Category::propsetCustom);
	}

	inline bool Atom::isProperty() const
	{
		return isPropertyGet() or isPropertySet() or isPropertySetCustom();
	}

	inline bool Atom::isUnittest() const
	{
		return category(Category::unittest);
	}

	inline bool Atom::isPublicOrPublished() const
	{
		return (visibility == nyv_public) or (visibility == nyv_published);
	}

	inline bool Atom::hasReturnType() const
	{
		return not returnType.clid.isVoid();
	}

	inline bool Atom::hasGenericParameters() const
	{
		return not tmplparams.empty();
	}

	inline bool Atom::isContextual() const
	{
		return hasGenericParameters() // generic classes
			or m_name.empty() // anonymous classes
			or (parent and parent->isFunction()); // anything inside a func which may depend from parameters
	}

	template<class C>
	inline void Atom::eachChild(const C& callback)
	{
		for (auto& pair: m_children)
		{
			if (not callback(*pair.second))
				return;
		}
	}

	template<class C>
	inline void Atom::eachChild(const C& callback) const
	{
		for (auto& pair: m_children)
		{
			if (not callback(*pair.second))
				return;
		}
	}

	inline bool Atom::hasMember(const AnyString& name) const
	{
		switch (type)
		{
			case Type::funcdef: return category(Category::functor);
			default:            return (m_children.count(name) != 0);
		}
		return false;
	}

	template<class C>
	inline void Atom::eachChild(const AnyString& needle, const C& callback)
	{
		assert(not needle.empty());
		auto range = m_children.equal_range(needle);
		for (auto it = range.first; it != range.second; ++it)
		{
			if (not callback(*(it->second)))
				return;
		}
	}

	template<class C>
	inline void Atom::eachChild(const AnyString& needle, const C& callback) const
	{
		assert(not needle.empty());
		auto range = m_children.equal_range(needle);
		for (auto it = range.first; it != range.second; ++it)
		{
			if (not callback(*(it->second)))
				return;
		}
	}

	inline void Atom::Parameters::swap(Parameters& rhs)
	{
		std::swap(pData, rhs.pData);
		std::swap(shortcircuitValue, rhs.shortcircuitValue);
	}

	template<class T>
	inline void Atom::Parameters::each(const T& callback) const
	{
		if (!!pData)
		{
			uint32_t count = pData->count;
			auto& params = pData->params;
			for (uint32_t i = 0; i != count; ++i)
			{
				auto& pair = params[i];
				callback(i, pair.first, pair.second);
			}
		}
	}

	inline uint Atom::Parameters::size() const
	{
		return (!!pData) ? pData.get()->count : 0;
	}

	inline bool Atom::Parameters::empty() const
	{
		return !pData;
	}

	inline bool Atom::Parameters::append(const CLID& clid, const AnyString& name)
	{
		if (!pData)
			pData = std::make_unique<Data>();
		auto& internal = *pData.get();

		if (likely(internal.count < Config::maxPushedParameters))
		{
			internal.params[internal.count].first  = name;
			internal.params[internal.count].second.clid = clid;
			++internal.count;
			return true;
		}
		return false;
	}

	inline yuint32 Atom::Parameters::findByName(const AnyString& name, yuint32 offset) const
	{
		if (!!pData)
		{
			auto& internal = *pData.get();
			uint32_t count = internal.count;
			for (uint32_t i = offset; i < count; ++i)
			{
				if (name == internal.params[i].first)
					return i;
			}
		}
		return static_cast<yuint32>(-1);
	}

	inline const AnyString& Atom::Parameters::name(uint index) const
	{
		assert(!!pData and index < pData->count);
		return pData->params[index].first;
	}

	inline const Vardef& Atom::Parameters::vardef(uint index) const
	{
		assert(!!pData and index < pData->count);
		return pData->params[index].second;
	}

	inline const std::pair<AnyString, Vardef>& Atom::Parameters::operator [] (uint index) const
	{
		assert(!!pData and index < pData->count);
		return pData->params[index];
	}

	inline uint64_t Atom::runtimeSizeof() const
	{
		return classinfo.nextFieldIndex * sizeof(uint64_t);
	}

	inline uint32_t Atom::childrenCount() const
	{
		return (uint32_t) m_children.size();
	}

	inline bool Atom::hasChildren() const
	{
		return not m_children.empty();
	}

	inline Atom::InstantiationRef Atom::instantiation(uint32_t index) const
	{
		return InstantiationRef{*this, index};
	}

	inline const IR::Sequence* Atom::InstantiationRef::sequenceIfExists() const
	{
		return (m_index < m_atom.instances.size()) ? m_atom.instances[m_index].get() : nullptr;
	}

	inline const IR::Sequence& Atom::InstantiationRef::sequence() const
	{
		assert(m_index < m_atom.instances.size());
		return *(m_atom.instances[m_index].get());
	}

	inline AnyString Atom::InstantiationRef::symbolname() const
	{
		return (m_index < m_atom.instances.size())
			? AnyString{m_atom.m_instancesMD[m_index].symbol} : AnyString{};
	}

} // namespace Nany
<commit_msg>atom: invalid 'hasMember' for functions<commit_after>#pragma once
#include "atom.h"

namespace Nany
{

	inline Atom* Atom::parentScope()
	{
		return (!scopeForNameResolution) ? parent : scopeForNameResolution;
	}

	inline const Atom* Atom::parentScope() const
	{
		return (!scopeForNameResolution) ? parent : scopeForNameResolution;
	}

	inline AnyString Atom::name() const
	{
		return m_name;
	}

	inline bool Atom::canCaptureVariabes() const
	{
		return flags.has(Flags::captureVariables)
			or (isClassMember() and parent->flags.has(Flags::captureVariables));
	}

	inline Atom* Atom::createDummy()
	{
		return new Atom("", Type::classdef);
	}

	inline CLID Atom::clid() const
	{
		return CLID::AtomMapID(atomid);
	}

	inline bool Atom::isNamespace() const
	{
		return type == Type::namespacedef;
	}

	inline bool Atom::isClass() const
	{
		return type == Type::classdef;
	}

	inline bool Atom::isAnonymousClass() const
	{
		return type == Type::classdef and m_name.empty();
	}

	inline bool Atom::isCtor() const
	{
		return category(Category::ctor);
	}

	inline bool Atom::isDtor() const
	{
		return category(Category::dtor);
	}

	inline bool Atom::isCloneCtor() const
	{
		return category(Category::clone);
	}

	inline bool Atom::isUnit() const
	{
		return type == Type::unit;
	}

	inline bool Atom::isTypeAlias() const
	{
		return type == Type::typealias;
	}

	inline bool Atom::isFunction() const
	{
		return type == Type::funcdef;
	}

	inline bool Atom::isOperator() const
	{
		return category(Category::funcoperator);
	}

	inline bool Atom::isSpecial() const
	{
		return category(Category::special);
	}

	inline bool Atom::isView() const
	{
		return category(Category::view);
	}

	inline bool Atom::isFunctor() const
	{
		return category(Category::functor);
	}

	inline bool Atom::isCapturedVariable() const
	{
		return category(Category::capturedVar);
	}

	inline bool Atom::isMemberVarDefaultInit() const
	{
		return category(Category::defvarInit);
	}

	inline bool Atom::isMemberVariable() const
	{
		return (type == Type::vardef) and category(Category::classParent);
	}

	inline bool Atom::isClassMember() const
	{
		return (type != Type::classdef) and category(Category::classParent);
	}

	inline bool Atom::isPropertyGet() const
	{
		return category(Category::propget);
	}

	inline bool Atom::isPropertySet() const
	{
		return category(Category::propset);
	}

	inline bool Atom::isPropertySetCustom() const
	{
		return category(Category::propsetCustom);
	}

	inline bool Atom::isProperty() const
	{
		return isPropertyGet() or isPropertySet() or isPropertySetCustom();
	}

	inline bool Atom::isUnittest() const
	{
		return category(Category::unittest);
	}

	inline bool Atom::isPublicOrPublished() const
	{
		return (visibility == nyv_public) or (visibility == nyv_published);
	}

	inline bool Atom::hasReturnType() const
	{
		return not returnType.clid.isVoid();
	}

	inline bool Atom::hasGenericParameters() const
	{
		return not tmplparams.empty();
	}

	inline bool Atom::isContextual() const
	{
		return hasGenericParameters() // generic classes
			or m_name.empty() // anonymous classes
			or (parent and parent->isFunction()); // anything inside a func which may depend from parameters
	}

	template<class C>
	inline void Atom::eachChild(const C& callback)
	{
		for (auto& pair: m_children)
		{
			if (not callback(*pair.second))
				return;
		}
	}

	template<class C>
	inline void Atom::eachChild(const C& callback) const
	{
		for (auto& pair: m_children)
		{
			if (not callback(*pair.second))
				return;
		}
	}

	inline bool Atom::hasMember(const AnyString& name) const
	{
		return (m_children.count(name) != 0);
	}

	template<class C>
	inline void Atom::eachChild(const AnyString& needle, const C& callback)
	{
		assert(not needle.empty());
		auto range = m_children.equal_range(needle);
		for (auto it = range.first; it != range.second; ++it)
		{
			if (not callback(*(it->second)))
				return;
		}
	}

	template<class C>
	inline void Atom::eachChild(const AnyString& needle, const C& callback) const
	{
		assert(not needle.empty());
		auto range = m_children.equal_range(needle);
		for (auto it = range.first; it != range.second; ++it)
		{
			if (not callback(*(it->second)))
				return;
		}
	}

	inline void Atom::Parameters::swap(Parameters& rhs)
	{
		std::swap(pData, rhs.pData);
		std::swap(shortcircuitValue, rhs.shortcircuitValue);
	}

	template<class T>
	inline void Atom::Parameters::each(const T& callback) const
	{
		if (!!pData)
		{
			uint32_t count = pData->count;
			auto& params = pData->params;
			for (uint32_t i = 0; i != count; ++i)
			{
				auto& pair = params[i];
				callback(i, pair.first, pair.second);
			}
		}
	}

	inline uint Atom::Parameters::size() const
	{
		return (!!pData) ? pData.get()->count : 0;
	}

	inline bool Atom::Parameters::empty() const
	{
		return !pData;
	}

	inline bool Atom::Parameters::append(const CLID& clid, const AnyString& name)
	{
		if (!pData)
			pData = std::make_unique<Data>();
		auto& internal = *pData.get();

		if (likely(internal.count < Config::maxPushedParameters))
		{
			internal.params[internal.count].first  = name;
			internal.params[internal.count].second.clid = clid;
			++internal.count;
			return true;
		}
		return false;
	}

	inline yuint32 Atom::Parameters::findByName(const AnyString& name, yuint32 offset) const
	{
		if (!!pData)
		{
			auto& internal = *pData.get();
			uint32_t count = internal.count;
			for (uint32_t i = offset; i < count; ++i)
			{
				if (name == internal.params[i].first)
					return i;
			}
		}
		return static_cast<yuint32>(-1);
	}

	inline const AnyString& Atom::Parameters::name(uint index) const
	{
		assert(!!pData and index < pData->count);
		return pData->params[index].first;
	}

	inline const Vardef& Atom::Parameters::vardef(uint index) const
	{
		assert(!!pData and index < pData->count);
		return pData->params[index].second;
	}

	inline const std::pair<AnyString, Vardef>& Atom::Parameters::operator [] (uint index) const
	{
		assert(!!pData and index < pData->count);
		return pData->params[index];
	}

	inline uint64_t Atom::runtimeSizeof() const
	{
		return classinfo.nextFieldIndex * sizeof(uint64_t);
	}

	inline uint32_t Atom::childrenCount() const
	{
		return (uint32_t) m_children.size();
	}

	inline bool Atom::hasChildren() const
	{
		return not m_children.empty();
	}

	inline Atom::InstantiationRef Atom::instantiation(uint32_t index) const
	{
		return InstantiationRef{*this, index};
	}

	inline const IR::Sequence* Atom::InstantiationRef::sequenceIfExists() const
	{
		return (m_index < m_atom.instances.size()) ? m_atom.instances[m_index].get() : nullptr;
	}

	inline const IR::Sequence& Atom::InstantiationRef::sequence() const
	{
		assert(m_index < m_atom.instances.size());
		return *(m_atom.instances[m_index].get());
	}

	inline AnyString Atom::InstantiationRef::symbolname() const
	{
		return (m_index < m_atom.instances.size())
			? AnyString{m_atom.m_instancesMD[m_index].symbol} : AnyString{};
	}

} // namespace Nany
<|endoftext|>


<commit_before>/*
 Copyright (c) 2014, The Cinder Project

 This code is intended to be used with the Cinder C++ library, http://libcinder.org

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#if( _WIN32_WINNT >= _WIN32_WINNT_VISTA )

#include "cinder/audio/msw/DeviceManagerWasapi.h"
#include "cinder/audio/msw/MswUtil.h"

#include "cinder/CinderAssert.h"
#include "cinder/audio/Debug.h"

#include "cinder/Utilities.h"
#include "cinder/msw/CinderMsw.h"

#include <setupapi.h>
#pragma comment(lib, "setupapi.lib")

#include <initguid.h> // must be included before mmdeviceapi.h for the pkey defines to be properly instantiated. Both must be first included from a translation unit.
#include <mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>

// TODO: I don't know of any way to get a device's preferred blocksize on windows, if it exists.
// - if it doesn't need a way to tell the user they should not listen to this value,
//   or we can use a pretty standard default (like 512 or 1024).
// - IAudioClient::GetBufferSize seems to be a possiblity, needs to be activated first
#define PREFERRED_FRAMES_PER_BLOCK 512

using namespace std;

namespace cinder { namespace audio { namespace msw {

// ----------------------------------------------------------------------------------------------------
// MARK: - DeviceManagerWasapi
// ----------------------------------------------------------------------------------------------------

DeviceRef DeviceManagerWasapi::getDefaultOutput()
{
	::IMMDeviceEnumerator *enumerator;
	HRESULT hr = ::CoCreateInstance( __uuidof(::MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(::IMMDeviceEnumerator), (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr = ci::msw::makeComUnique( enumerator );

	::IMMDevice *device;
	hr = enumerator->GetDefaultAudioEndpoint( eRender, eConsole, &device );
	CI_ASSERT( hr == S_OK );

	auto devicePtr = ci::msw::makeComUnique( device );

	::LPWSTR idStr;
	device->GetId( &idStr );
	CI_ASSERT( idStr );

	string key( ci::toUtf8( idStr ) );
	::CoTaskMemFree( idStr );
	return findDeviceByKey( key );
}

DeviceRef DeviceManagerWasapi::getDefaultInput()
{
	::IMMDeviceEnumerator *enumerator;
	HRESULT hr = ::CoCreateInstance( __uuidof(::MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(::IMMDeviceEnumerator), (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr = ci::msw::makeComUnique( enumerator );

	::IMMDevice *device;
	hr = enumerator->GetDefaultAudioEndpoint( eCapture, eConsole, &device );
	CI_ASSERT( hr == S_OK );

	auto devicePtr = ci::msw::makeComUnique( device );

	::LPWSTR idStr;
	device->GetId( &idStr );
	CI_ASSERT( idStr );

	string key( ci::toUtf8( idStr ) );
	::CoTaskMemFree( idStr );

	return findDeviceByKey( key );
}

const std::vector<DeviceRef>& DeviceManagerWasapi::getDevices()
{
	if( mDevices.empty() ) {
		parseDevices( DeviceInfo::Usage::INPUT );
		parseDevices( DeviceInfo::Usage::OUTPUT );
	}
	return mDevices;
}

std::string DeviceManagerWasapi::getName( const DeviceRef &device )
{
	return getDeviceInfo( device ).mName;
}

size_t DeviceManagerWasapi::getNumInputChannels( const DeviceRef &device )
{
	auto& devInfo = getDeviceInfo( device );
	if( devInfo.mUsage != DeviceInfo::Usage::INPUT )
		return 0;

	return devInfo.mNumChannels;
}

size_t DeviceManagerWasapi::getNumOutputChannels( const DeviceRef &device )
{
	auto& devInfo = getDeviceInfo( device );
	if( devInfo.mUsage != DeviceInfo::Usage::OUTPUT )
		return 0;

	return devInfo.mNumChannels;
}

size_t DeviceManagerWasapi::getSampleRate( const DeviceRef &device )
{
	return getDeviceInfo( device ).mSampleRate;
}

size_t DeviceManagerWasapi::getFramesPerBlock( const DeviceRef &device )
{
	size_t frames = getDeviceInfo( device ).mFramesPerBlock;
	//return getDeviceInfo( device ).mFramesPerBlock;
	return frames;
}

// TODO: it is really only possible to change the devices samplerate in exclusive mode
// - but this is a kludge to allow context's other samplerates / block sizes until Context handles it.
void DeviceManagerWasapi::setSampleRate( const DeviceRef &device, size_t sampleRate )
{
	//throw AudioDeviceExc( "Samplerate cannot be changed for Wasapi devices in shared mode." );
	getDeviceInfo( device ).mSampleRate = sampleRate;
	emitParamsDidChange( device );
}

void DeviceManagerWasapi::setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock )
{
	//throw AudioDeviceExc( "Frames per block changes not supported for Wasapi devices." );

	// also temp kludge:
	getDeviceInfo( device ).mFramesPerBlock = framesPerBlock;
	emitParamsDidChange( device );
}

const std::wstring& DeviceManagerWasapi::getDeviceId( const DeviceRef &device )
{
	return getDeviceInfo( device ).mDeviceId;
}

shared_ptr<::IMMDevice> DeviceManagerWasapi::getIMMDevice( const DeviceRef &device )
{
	::IMMDeviceEnumerator *enumerator;
	HRESULT hr = ::CoCreateInstance( __uuidof(::MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(::IMMDeviceEnumerator), (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr = ci::msw::makeComUnique( enumerator );

	::IMMDevice *deviceImm;
	const wstring &endpointId = getDeviceInfo( device ).mEndpointId;
	hr = enumerator->GetDevice( endpointId.c_str(), &deviceImm );
	CI_ASSERT( hr == S_OK );

	return 	ci::msw::makeComShared( deviceImm );
}

// ----------------------------------------------------------------------------------------------------
// MARK: - Private
// ----------------------------------------------------------------------------------------------------

DeviceManagerWasapi::DeviceInfo& DeviceManagerWasapi::getDeviceInfo( const DeviceRef &device )
{
	return mDeviceInfoSet.at( device );
}

// This call is performed twice because a separate Device subclass is used for input and output
// and by using eRender / eCapture instead of eAll when enumerating the endpoints, it is easier
// to distinguish between the two.
// TODO: this isn't true any more, at the moment there are no Device subclasses, just DeviceManager subclasses
void DeviceManagerWasapi::parseDevices( DeviceInfo::Usage usage )
{
	const size_t kMaxPropertyStringLength = 2048;

	vector<wstring> deviceIds = parseDeviceIds( usage );

	::IMMDeviceEnumerator *enumerator;
	const ::CLSID CLSID_MMDeviceEnumerator = __uuidof( ::MMDeviceEnumerator );
	const ::IID IID_IMMDeviceEnumerator = __uuidof( ::IMMDeviceEnumerator );
	HRESULT hr = CoCreateInstance( CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr =  ci::msw::makeComUnique( enumerator );

	::EDataFlow dataFlow = ( usage == DeviceInfo::Usage::INPUT ? eCapture : eRender );
	::IMMDeviceCollection *devices;
	hr = enumerator->EnumAudioEndpoints( dataFlow, DEVICE_STATE_ACTIVE, &devices );
	CI_ASSERT( hr == S_OK );
	auto devicesPtr = ci::msw::makeComUnique( devices );

	UINT numDevices;
	hr = devices->GetCount( &numDevices );
	CI_ASSERT( hr == S_OK );

	for ( UINT i = 0; i < numDevices; i++ )	{
		DeviceInfo devInfo;
		devInfo.mUsage = usage;

		::IMMDevice *deviceImm;
		hr = devices->Item( i, &deviceImm );
		CI_ASSERT( hr == S_OK );
		auto devicePtr = ci::msw::makeComUnique( deviceImm );

		::IPropertyStore *properties;
		hr = deviceImm->OpenPropertyStore( STGM_READ, &properties );
		CI_ASSERT( hr == S_OK );
		auto propertiesPtr = ci::msw::makeComUnique( properties );

		::PROPVARIANT nameVar;
		hr = properties->GetValue( PKEY_Device_FriendlyName, &nameVar );
		CI_ASSERT( hr == S_OK );
		devInfo.mName = ci::toUtf8( nameVar.pwszVal );

		LPWSTR endpointIdLpwStr;
		hr = deviceImm->GetId( &endpointIdLpwStr );
		CI_ASSERT( hr == S_OK );
		devInfo.mEndpointId = wstring( endpointIdLpwStr );
		devInfo.mKey = ci::toUtf8( devInfo.mEndpointId );
		::CoTaskMemFree( endpointIdLpwStr );

		// Wasapi's device Id is actually a subset of the one xaudio needs, so we find and use the match.
		// TODO: add xaudio-specific method to get the required string from device, which does the formatting
		for( auto it = deviceIds.begin(); it != deviceIds.end(); ++it ) {
			if( it->find( devInfo.mEndpointId ) != wstring::npos ) {
				devInfo.mDeviceId = *it;
				deviceIds.erase( it );
				break;
			}
		}

		::PROPVARIANT formatVar;
		hr = properties->GetValue( PKEY_AudioEngine_DeviceFormat, &formatVar );
		CI_ASSERT( hr == S_OK );
		::WAVEFORMATEX *format = (::WAVEFORMATEX *)formatVar.blob.pBlobData;

		devInfo.mNumChannels = format->nChannels;
		devInfo.mSampleRate = format->nSamplesPerSec;
		devInfo.mFramesPerBlock = PREFERRED_FRAMES_PER_BLOCK;

		DeviceRef addedDevice = addDevice( devInfo.mKey );
		auto result = mDeviceInfoSet.insert( make_pair( addedDevice, devInfo ) );
	}
}

// This method uses the SetupDi api to recover device id strings that Xaudio2.8 needs for
// creating a mastering voice with non-default device
vector<wstring> DeviceManagerWasapi::parseDeviceIds( DeviceInfo::Usage usage )
{
	vector<wstring> result;
	DWORD deviceIndex = 0;
	::SP_DEVICE_INTERFACE_DATA devInterface = { 0 };
	devInterface.cbSize = sizeof( ::SP_DEVICE_INTERFACE_DATA );

	CONST ::GUID *devInterfaceGuid = ( usage == DeviceInfo::Usage::INPUT ? &DEVINTERFACE_AUDIO_CAPTURE : &DEVINTERFACE_AUDIO_RENDER );
	::HDEVINFO devInfoSet = ::SetupDiGetClassDevs( devInterfaceGuid, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT );
	if( devInfoSet == INVALID_HANDLE_VALUE ) {
		CI_LOG_E( "INVALID_HANDLE_VALUE, detailed error: " << GetLastError() );
		CI_ASSERT( false );
		return result;
	}

	while( true ) {
		if( ! ::SetupDiEnumDeviceInterfaces( devInfoSet, 0, devInterfaceGuid, deviceIndex, &devInterface ) ) {
			DWORD error = GetLastError();
			if( error == ERROR_NO_MORE_ITEMS )
				break;
			else {
				CI_LOG_E( "SetupDiEnumDeviceInterfaces returned error: " << error );
				CI_ASSERT( 0 );
			}
		}
		deviceIndex++;

		// See how large a buffer we require for the device interface details (ignore error, it should be returning ERROR_INSUFFICIENT_BUFFER)
		DWORD sizeDevInterface;
		::SetupDiGetDeviceInterfaceDetail( devInfoSet, &devInterface, 0, 0, &sizeDevInterface, 0 );

		shared_ptr<::SP_DEVICE_INTERFACE_DETAIL_DATA> interfaceDetail( (::SP_DEVICE_INTERFACE_DETAIL_DATA*)calloc( 1, sizeDevInterface ), free );
		CI_ASSERT( interfaceDetail );
		interfaceDetail->cbSize = sizeof( ::SP_DEVICE_INTERFACE_DETAIL_DATA );

		::SP_DEVINFO_DATA devInfo = {0};
		devInfo.cbSize = sizeof( ::SP_DEVINFO_DATA );
		if( ! ::SetupDiGetDeviceInterfaceDetail( devInfoSet, &devInterface, interfaceDetail.get(), sizeDevInterface, 0, &devInfo ) ) {
			continue;
			DWORD error = ::GetLastError();
			CI_LOG_E( "get device returned false. error: " << error );
		}

		result.push_back( wstring( interfaceDetail->DevicePath ) );
	}

	if( devInfoSet )
		::SetupDiDestroyDeviceInfoList( devInfoSet );

	return result;
}

} } } // namespace cinder::audio::msw

#endif // ( _WIN32_WINNT >= _WIN32_WINNT_VISTA )<commit_msg>update to new msw::toUtfString() method<commit_after>/*
 Copyright (c) 2014, The Cinder Project

 This code is intended to be used with the Cinder C++ library, http://libcinder.org

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#if( _WIN32_WINNT >= _WIN32_WINNT_VISTA )

#include "cinder/audio/msw/DeviceManagerWasapi.h"
#include "cinder/audio/msw/MswUtil.h"
#include "cinder/audio/Debug.h"
#include "cinder/CinderAssert.h"
#include "cinder/msw/CinderMsw.h"

#include <setupapi.h>
#pragma comment(lib, "setupapi.lib")

#include <initguid.h> // must be included before mmdeviceapi.h for the pkey defines to be properly instantiated. Both must be first included from a translation unit.
#include <mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>

// TODO: I don't know of any way to get a device's preferred blocksize on windows, if it exists.
// - if it doesn't need a way to tell the user they should not listen to this value,
//   or we can use a pretty standard default (like 512 or 1024).
// - IAudioClient::GetBufferSize seems to be a possiblity, needs to be activated first
#define PREFERRED_FRAMES_PER_BLOCK 512

using namespace std;

namespace cinder { namespace audio { namespace msw {

// ----------------------------------------------------------------------------------------------------
// MARK: - DeviceManagerWasapi
// ----------------------------------------------------------------------------------------------------

DeviceRef DeviceManagerWasapi::getDefaultOutput()
{
	::IMMDeviceEnumerator *enumerator;
	HRESULT hr = ::CoCreateInstance( __uuidof(::MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(::IMMDeviceEnumerator), (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr = ci::msw::makeComUnique( enumerator );

	::IMMDevice *device;
	hr = enumerator->GetDefaultAudioEndpoint( eRender, eConsole, &device );
	CI_ASSERT( hr == S_OK );

	auto devicePtr = ci::msw::makeComUnique( device );

	::LPWSTR idStr;
	device->GetId( &idStr );
	CI_ASSERT( idStr );

	string key( ci::msw::toUtf8String( idStr ) );
	::CoTaskMemFree( idStr );
	return findDeviceByKey( key );
}

DeviceRef DeviceManagerWasapi::getDefaultInput()
{
	::IMMDeviceEnumerator *enumerator;
	HRESULT hr = ::CoCreateInstance( __uuidof(::MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(::IMMDeviceEnumerator), (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr = ci::msw::makeComUnique( enumerator );

	::IMMDevice *device;
	hr = enumerator->GetDefaultAudioEndpoint( eCapture, eConsole, &device );
	CI_ASSERT( hr == S_OK );

	auto devicePtr = ci::msw::makeComUnique( device );

	::LPWSTR idStr;
	device->GetId( &idStr );
	CI_ASSERT( idStr );

	string key( ci::msw::toUtf8String( idStr ) );
	::CoTaskMemFree( idStr );

	return findDeviceByKey( key );
}

const std::vector<DeviceRef>& DeviceManagerWasapi::getDevices()
{
	if( mDevices.empty() ) {
		parseDevices( DeviceInfo::Usage::INPUT );
		parseDevices( DeviceInfo::Usage::OUTPUT );
	}
	return mDevices;
}

std::string DeviceManagerWasapi::getName( const DeviceRef &device )
{
	return getDeviceInfo( device ).mName;
}

size_t DeviceManagerWasapi::getNumInputChannels( const DeviceRef &device )
{
	auto& devInfo = getDeviceInfo( device );
	if( devInfo.mUsage != DeviceInfo::Usage::INPUT )
		return 0;

	return devInfo.mNumChannels;
}

size_t DeviceManagerWasapi::getNumOutputChannels( const DeviceRef &device )
{
	auto& devInfo = getDeviceInfo( device );
	if( devInfo.mUsage != DeviceInfo::Usage::OUTPUT )
		return 0;

	return devInfo.mNumChannels;
}

size_t DeviceManagerWasapi::getSampleRate( const DeviceRef &device )
{
	return getDeviceInfo( device ).mSampleRate;
}

size_t DeviceManagerWasapi::getFramesPerBlock( const DeviceRef &device )
{
	size_t frames = getDeviceInfo( device ).mFramesPerBlock;
	//return getDeviceInfo( device ).mFramesPerBlock;
	return frames;
}

// TODO: it is really only possible to change the devices samplerate in exclusive mode
// - but this is a kludge to allow context's other samplerates / block sizes until Context handles it.
void DeviceManagerWasapi::setSampleRate( const DeviceRef &device, size_t sampleRate )
{
	//throw AudioDeviceExc( "Samplerate cannot be changed for Wasapi devices in shared mode." );
	getDeviceInfo( device ).mSampleRate = sampleRate;
	emitParamsDidChange( device );
}

void DeviceManagerWasapi::setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock )
{
	//throw AudioDeviceExc( "Frames per block changes not supported for Wasapi devices." );

	// also temp kludge:
	getDeviceInfo( device ).mFramesPerBlock = framesPerBlock;
	emitParamsDidChange( device );
}

const std::wstring& DeviceManagerWasapi::getDeviceId( const DeviceRef &device )
{
	return getDeviceInfo( device ).mDeviceId;
}

shared_ptr<::IMMDevice> DeviceManagerWasapi::getIMMDevice( const DeviceRef &device )
{
	::IMMDeviceEnumerator *enumerator;
	HRESULT hr = ::CoCreateInstance( __uuidof(::MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(::IMMDeviceEnumerator), (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr = ci::msw::makeComUnique( enumerator );

	::IMMDevice *deviceImm;
	const wstring &endpointId = getDeviceInfo( device ).mEndpointId;
	hr = enumerator->GetDevice( endpointId.c_str(), &deviceImm );
	CI_ASSERT( hr == S_OK );

	return 	ci::msw::makeComShared( deviceImm );
}

// ----------------------------------------------------------------------------------------------------
// MARK: - Private
// ----------------------------------------------------------------------------------------------------

DeviceManagerWasapi::DeviceInfo& DeviceManagerWasapi::getDeviceInfo( const DeviceRef &device )
{
	return mDeviceInfoSet.at( device );
}

// This call is performed twice because a separate Device subclass is used for input and output
// and by using eRender / eCapture instead of eAll when enumerating the endpoints, it is easier
// to distinguish between the two.
// TODO: this isn't true any more, at the moment there are no Device subclasses, just DeviceManager subclasses
void DeviceManagerWasapi::parseDevices( DeviceInfo::Usage usage )
{
	const size_t kMaxPropertyStringLength = 2048;

	vector<wstring> deviceIds = parseDeviceIds( usage );

	::IMMDeviceEnumerator *enumerator;
	const ::CLSID CLSID_MMDeviceEnumerator = __uuidof( ::MMDeviceEnumerator );
	const ::IID IID_IMMDeviceEnumerator = __uuidof( ::IMMDeviceEnumerator );
	HRESULT hr = CoCreateInstance( CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enumerator );
	CI_ASSERT( hr == S_OK );
	auto enumeratorPtr =  ci::msw::makeComUnique( enumerator );

	::EDataFlow dataFlow = ( usage == DeviceInfo::Usage::INPUT ? eCapture : eRender );
	::IMMDeviceCollection *devices;
	hr = enumerator->EnumAudioEndpoints( dataFlow, DEVICE_STATE_ACTIVE, &devices );
	CI_ASSERT( hr == S_OK );
	auto devicesPtr = ci::msw::makeComUnique( devices );

	UINT numDevices;
	hr = devices->GetCount( &numDevices );
	CI_ASSERT( hr == S_OK );

	for ( UINT i = 0; i < numDevices; i++ )	{
		DeviceInfo devInfo;
		devInfo.mUsage = usage;

		::IMMDevice *deviceImm;
		hr = devices->Item( i, &deviceImm );
		CI_ASSERT( hr == S_OK );
		auto devicePtr = ci::msw::makeComUnique( deviceImm );

		::IPropertyStore *properties;
		hr = deviceImm->OpenPropertyStore( STGM_READ, &properties );
		CI_ASSERT( hr == S_OK );
		auto propertiesPtr = ci::msw::makeComUnique( properties );

		::PROPVARIANT nameVar;
		hr = properties->GetValue( PKEY_Device_FriendlyName, &nameVar );
		CI_ASSERT( hr == S_OK );
		devInfo.mName = ci::msw::toUtf8String( nameVar.pwszVal );

		LPWSTR endpointIdLpwStr;
		hr = deviceImm->GetId( &endpointIdLpwStr );
		CI_ASSERT( hr == S_OK );
		devInfo.mEndpointId = wstring( endpointIdLpwStr );
		devInfo.mKey = ci::msw::toUtf8String( devInfo.mEndpointId );
		::CoTaskMemFree( endpointIdLpwStr );

		// Wasapi's device Id is actually a subset of the one xaudio needs, so we find and use the match.
		// TODO: add xaudio-specific method to get the required string from device, which does the formatting
		for( auto it = deviceIds.begin(); it != deviceIds.end(); ++it ) {
			if( it->find( devInfo.mEndpointId ) != wstring::npos ) {
				devInfo.mDeviceId = *it;
				deviceIds.erase( it );
				break;
			}
		}

		::PROPVARIANT formatVar;
		hr = properties->GetValue( PKEY_AudioEngine_DeviceFormat, &formatVar );
		CI_ASSERT( hr == S_OK );
		::WAVEFORMATEX *format = (::WAVEFORMATEX *)formatVar.blob.pBlobData;

		devInfo.mNumChannels = format->nChannels;
		devInfo.mSampleRate = format->nSamplesPerSec;
		devInfo.mFramesPerBlock = PREFERRED_FRAMES_PER_BLOCK;

		DeviceRef addedDevice = addDevice( devInfo.mKey );
		auto result = mDeviceInfoSet.insert( make_pair( addedDevice, devInfo ) );
	}
}

// This method uses the SetupDi api to recover device id strings that Xaudio2.8 needs for
// creating a mastering voice with non-default device
vector<wstring> DeviceManagerWasapi::parseDeviceIds( DeviceInfo::Usage usage )
{
	vector<wstring> result;
	DWORD deviceIndex = 0;
	::SP_DEVICE_INTERFACE_DATA devInterface = { 0 };
	devInterface.cbSize = sizeof( ::SP_DEVICE_INTERFACE_DATA );

	CONST ::GUID *devInterfaceGuid = ( usage == DeviceInfo::Usage::INPUT ? &DEVINTERFACE_AUDIO_CAPTURE : &DEVINTERFACE_AUDIO_RENDER );
	::HDEVINFO devInfoSet = ::SetupDiGetClassDevs( devInterfaceGuid, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT );
	if( devInfoSet == INVALID_HANDLE_VALUE ) {
		CI_LOG_E( "INVALID_HANDLE_VALUE, detailed error: " << GetLastError() );
		CI_ASSERT( false );
		return result;
	}

	while( true ) {
		if( ! ::SetupDiEnumDeviceInterfaces( devInfoSet, 0, devInterfaceGuid, deviceIndex, &devInterface ) ) {
			DWORD error = GetLastError();
			if( error == ERROR_NO_MORE_ITEMS )
				break;
			else {
				CI_LOG_E( "SetupDiEnumDeviceInterfaces returned error: " << error );
				CI_ASSERT( 0 );
			}
		}
		deviceIndex++;

		// See how large a buffer we require for the device interface details (ignore error, it should be returning ERROR_INSUFFICIENT_BUFFER)
		DWORD sizeDevInterface;
		::SetupDiGetDeviceInterfaceDetail( devInfoSet, &devInterface, 0, 0, &sizeDevInterface, 0 );

		shared_ptr<::SP_DEVICE_INTERFACE_DETAIL_DATA> interfaceDetail( (::SP_DEVICE_INTERFACE_DETAIL_DATA*)calloc( 1, sizeDevInterface ), free );
		CI_ASSERT( interfaceDetail );
		interfaceDetail->cbSize = sizeof( ::SP_DEVICE_INTERFACE_DETAIL_DATA );

		::SP_DEVINFO_DATA devInfo = {0};
		devInfo.cbSize = sizeof( ::SP_DEVINFO_DATA );
		if( ! ::SetupDiGetDeviceInterfaceDetail( devInfoSet, &devInterface, interfaceDetail.get(), sizeDevInterface, 0, &devInfo ) ) {
			continue;
			DWORD error = ::GetLastError();
			CI_LOG_E( "get device returned false. error: " << error );
		}

		result.push_back( wstring( interfaceDetail->DevicePath ) );
	}

	if( devInfoSet )
		::SetupDiDestroyDeviceInfoList( devInfoSet );

	return result;
}

} } } // namespace cinder::audio::msw

#endif // ( _WIN32_WINNT >= _WIN32_WINNT_VISTA )<|endoftext|>


<commit_before>/*
Reproducing xfstest generic/325

1. Create file foo and write some contents 0-256K into it and sync it
2. mmap write 0-4K to file foo
3. mmap write 252K - 256K to file foo
4. msync both the regions

After a crash, contents of file foo must be persisted.

https://patchwork.kernel.org/patch/4824621/
*/

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <dirent.h>
#include <cstring>
#include <errno.h>
#include <sys/mman.h>
#include "BaseTestCase.h"
#include "../user_tools/api/workload.h"
#include "../user_tools/api/actions.h"
#define TEST_FILE_FOO "foo"
#define TEST_FILE_FOO_BACKUP "foo_backup"

using fs_testing::tests::DataTestResult;
using fs_testing::user_tools::api::WriteData;
using fs_testing::user_tools::api::WriteDataMmap;
using fs_testing::user_tools::api::Checkpoint;
using std::string;

#define TEST_FILE_PERMS  ((mode_t) (S_IRWXU | S_IRWXG | S_IRWXO))

namespace fs_testing {
namespace tests {

class Generic325: public BaseTestCase {
 public:
  virtual int setup() override {

	init_paths();

    const int fd_Afoo = open(foo_backup_path.c_str(), O_RDWR | O_CREAT, TEST_FILE_PERMS);
    if (fd_Afoo < 0) {
      return -1;
    }

    // Write some contents to the backup file (for verifying md5sum in check_test)
    if (WriteData(fd_Afoo, 0, 262144) < 0) {
    	return -2;
    }

    sync();

    char *filep_Afoo = (char *) mmap(NULL, 262144, PROT_WRITE|PROT_READ, MAP_SHARED, fd_Afoo, 0);
    if (filep_Afoo == MAP_FAILED) {
	return -1;
    }

    int offset_Afoo = 0;
    int to_write_Afoo = 4096 ;
    const char *text_Afoo  = "12345678123456781234567812345678";

    while (offset_Afoo < 4096){
	if (to_write_Afoo < 32){
		memcpy(filep_Afoo + offset_Afoo, text_Afoo, to_write_Afoo);
		offset_Afoo += to_write_Afoo;
	}
	else {
		memcpy(filep_Afoo + offset_Afoo ,text_Afoo, 32);
		offset_Afoo += 32;
	}
     }

     if ( msync ( filep_Afoo, 65536 , MS_SYNC) < 0){
	munmap( filep_Afoo, 65536);
	return -1;
     }

  offset_Afoo = 0;
   while (offset_Afoo < 4096){
        if (to_write_Afoo < 32){
                memcpy(filep_Afoo +258048+ offset_Afoo, text_Afoo, to_write_Afoo);
                offset_Afoo += to_write_Afoo;
        }
        else {
                memcpy(filep_Afoo+258048+ offset_Afoo,text_Afoo, 32);
                offset_Afoo += 32;
        }
     }

     if ( msync ( filep_Afoo+196608, 65536 , MS_SYNC) < 0){
        munmap( filep_Afoo+65536, 196608);
        return -1;
     }
     munmap( filep_Afoo, 262144);

    sync();
    close(fd_Afoo);

    return 0;
  }

  virtual int run() override {

	init_paths();

    const int fd_Afoo = open(foo_path.c_str(), O_RDWR | O_CREAT, TEST_FILE_PERMS);
    if (fd_Afoo < 0) {
      return -1;
    }
    if (WriteData(fd_Afoo, 0, 262144) < 0) {
        return -2;
    }

   sync();

   char *filep_Afoo = (char *) mmap(NULL, 262144, PROT_WRITE|PROT_READ, MAP_SHARED, fd_Afoo, 0);
    if (filep_Afoo == MAP_FAILED) {
        return -1;
    }

    int offset_Afoo = 0;
    int to_write_Afoo = 4096 ;
    const char *text_Afoo  = "12345678123456781234567812345678";

    while (offset_Afoo < 4096){
        if (to_write_Afoo < 32){
                memcpy(filep_Afoo + offset_Afoo, text_Afoo, to_write_Afoo);
                offset_Afoo += to_write_Afoo;
        }
        else {
                memcpy(filep_Afoo + offset_Afoo ,text_Afoo, 32);
                offset_Afoo += 32;
        }
     }

  offset_Afoo = 0;
   while (offset_Afoo < 4096){
        if (to_write_Afoo < 32){
                memcpy(filep_Afoo +258048+ offset_Afoo, text_Afoo, to_write_Afoo);
                offset_Afoo += to_write_Afoo;
        }
        else {
                memcpy(filep_Afoo+258048+ offset_Afoo,text_Afoo, 32);
                offset_Afoo += 32;
        }
     }

     if ( msync ( filep_Afoo, 65536 , MS_SYNC) < 0){
        munmap( filep_Afoo, 65536);
        return -1;
     }

     if ( msync ( filep_Afoo+196608, 65536 , MS_SYNC) < 0){
        munmap( filep_Afoo+65536, 196608);
        return -1;
     }
     munmap( filep_Afoo, 262144);

     if (Checkpoint() < 0)
        return -1;

    close(fd_Afoo);

    return 0;
  }

  virtual int check_test(unsigned int last_checkpoint,
      DataTestResult *test_result) override {

	init_paths();

        if (last_checkpoint >= 1){
		string expected_md5sum = get_md5sum(foo_backup_path);
		string actual_md5sum = get_md5sum(foo_path);

		if (expected_md5sum.compare(actual_md5sum) != 0 ) {
        		test_result->SetError(DataTestResult::kFileDataCorrupted);
        		test_result->error_description = " : md5sum of bar does not match with expected md5sum of foo backup";
		}
	}

    return 0;
  }

   private:
    string foo_path;
    string foo_backup_path;

    void init_paths() {
        foo_path = mnt_dir_ +  "/" TEST_FILE_FOO;
        foo_backup_path = mnt_dir_ +  "/" TEST_FILE_FOO_BACKUP;
    }

    string get_md5sum(string file_name) {
        FILE *fp;
        string command = "md5sum " + file_name;

        fp = popen(command.c_str(), "r");
        char md5[100];
        fscanf(fp,"%s", md5);
        fclose(fp);

        string md5_str(md5);
        return md5_str;
    }

};

}  // namespace tests
}  // namespace fs_testing

extern "C" fs_testing::tests::BaseTestCase *test_case_get_instance() {
  return new fs_testing::tests::Generic325;
}

extern "C" void test_case_delete_instance(fs_testing::tests::BaseTestCase *tc) {
  delete tc;
}
<commit_msg>Another test template modification due to merge<commit_after>/*
Reproducing xfstest generic/325

1. Create file foo and write some contents 0-256K into it and sync it
2. mmap write 0-4K to file foo
3. mmap write 252K - 256K to file foo
4. msync both the regions

After a crash, contents of file foo must be persisted.

https://patchwork.kernel.org/patch/4824621/
*/

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <dirent.h>
#include <cstring>
#include <errno.h>
#include <sys/mman.h>
#include "BaseTestCase.h"
#include "../user_tools/api/workload.h"
#include "../user_tools/api/actions.h"
#define TEST_FILE_FOO "foo"
#define TEST_FILE_FOO_BACKUP "foo_backup"

using fs_testing::tests::DataTestResult;
using fs_testing::user_tools::api::WriteData;
using fs_testing::user_tools::api::WriteDataMmap;
using fs_testing::user_tools::api::Checkpoint;
using std::string;

#define TEST_FILE_PERMS  ((mode_t) (S_IRWXU | S_IRWXG | S_IRWXO))

namespace fs_testing {
namespace tests {

class Generic325: public BaseTestCase {
 public:
  virtual int setup() override {

	init_paths();

    const int fd_Afoo = open(foo_backup_path.c_str(), O_RDWR | O_CREAT, TEST_FILE_PERMS);
    if (fd_Afoo < 0) {
      return -1;
    }

    // Write some contents to the backup file (for verifying md5sum in check_test)
    if (WriteData(fd_Afoo, 0, 262144) < 0) {
    	return -2;
    }

    sync();

    char *filep_Afoo = (char *) mmap(NULL, 262144, PROT_WRITE|PROT_READ, MAP_SHARED, fd_Afoo, 0);
    if (filep_Afoo == MAP_FAILED) {
	return -1;
    }

    int offset_Afoo = 0;
    int to_write_Afoo = 4096 ;
    const char *text_Afoo  = "12345678123456781234567812345678";

    while (offset_Afoo < 4096){
	if (to_write_Afoo < 32){
		memcpy(filep_Afoo + offset_Afoo, text_Afoo, to_write_Afoo);
		offset_Afoo += to_write_Afoo;
	}
	else {
		memcpy(filep_Afoo + offset_Afoo ,text_Afoo, 32);
		offset_Afoo += 32;
	}
     }

     if ( msync ( filep_Afoo, 65536 , MS_SYNC) < 0){
	munmap( filep_Afoo, 65536);
	return -1;
     }

  offset_Afoo = 0;
   while (offset_Afoo < 4096){
        if (to_write_Afoo < 32){
                memcpy(filep_Afoo +258048+ offset_Afoo, text_Afoo, to_write_Afoo);
                offset_Afoo += to_write_Afoo;
        }
        else {
                memcpy(filep_Afoo+258048+ offset_Afoo,text_Afoo, 32);
                offset_Afoo += 32;
        }
     }

     if ( msync ( filep_Afoo+196608, 65536 , MS_SYNC) < 0){
        munmap( filep_Afoo+65536, 196608);
        return -1;
     }
     munmap( filep_Afoo, 262144);

    sync();
    close(fd_Afoo);

    return 0;
  }

  virtual int run(int checkpoint) override {

	int local_checkpoint = 0;
	init_paths();

    const int fd_Afoo = open(foo_path.c_str(), O_RDWR | O_CREAT, TEST_FILE_PERMS);
    if (fd_Afoo < 0) {
      return -1;
    }
    if (WriteData(fd_Afoo, 0, 262144) < 0) {
        return -2;
    }

   sync();

   char *filep_Afoo = (char *) mmap(NULL, 262144, PROT_WRITE|PROT_READ, MAP_SHARED, fd_Afoo, 0);
    if (filep_Afoo == MAP_FAILED) {
        return -1;
    }

    int offset_Afoo = 0;
    int to_write_Afoo = 4096 ;
    const char *text_Afoo  = "12345678123456781234567812345678";

    while (offset_Afoo < 4096){
        if (to_write_Afoo < 32){
                memcpy(filep_Afoo + offset_Afoo, text_Afoo, to_write_Afoo);
                offset_Afoo += to_write_Afoo;
        }
        else {
                memcpy(filep_Afoo + offset_Afoo ,text_Afoo, 32);
                offset_Afoo += 32;
        }
     }

  offset_Afoo = 0;
   while (offset_Afoo < 4096){
        if (to_write_Afoo < 32){
                memcpy(filep_Afoo +258048+ offset_Afoo, text_Afoo, to_write_Afoo);
                offset_Afoo += to_write_Afoo;
        }
        else {
                memcpy(filep_Afoo+258048+ offset_Afoo,text_Afoo, 32);
                offset_Afoo += 32;
        }
     }

     if ( msync ( filep_Afoo, 65536 , MS_SYNC) < 0){
        munmap( filep_Afoo, 65536);
        return -1;
     }

     if ( msync ( filep_Afoo+196608, 65536 , MS_SYNC) < 0){
        munmap( filep_Afoo+65536, 196608);
        return -1;
     }
     munmap( filep_Afoo, 262144);

     if (Checkpoint() < 0)
        return -1;

    local_checkpoint += 1;
    if (local_checkpoint == checkpoint){
	return 1;
    }

    close(fd_Afoo);

    return 0;
  }

  virtual int check_test(unsigned int last_checkpoint,
      DataTestResult *test_result) override {

	init_paths();

        if (last_checkpoint >= 1){
		string expected_md5sum = get_md5sum(foo_backup_path);
		string actual_md5sum = get_md5sum(foo_path);

		if (expected_md5sum.compare(actual_md5sum) != 0 ) {
        		test_result->SetError(DataTestResult::kFileDataCorrupted);
        		test_result->error_description = " : md5sum of bar does not match with expected md5sum of foo backup";
		}
	}

    return 0;
  }

   private:
    string foo_path;
    string foo_backup_path;

    void init_paths() {
        foo_path = mnt_dir_ +  "/" TEST_FILE_FOO;
        foo_backup_path = mnt_dir_ +  "/" TEST_FILE_FOO_BACKUP;
    }

    string get_md5sum(string file_name) {
        FILE *fp;
        string command = "md5sum " + file_name;

        fp = popen(command.c_str(), "r");
        char md5[100];
        fscanf(fp,"%s", md5);
        fclose(fp);

        string md5_str(md5);
        return md5_str;
    }

};

}  // namespace tests
}  // namespace fs_testing

extern "C" fs_testing::tests::BaseTestCase *test_case_get_instance() {
  return new fs_testing::tests::Generic325;
}

extern "C" void test_case_delete_instance(fs_testing::tests::BaseTestCase *tc) {
  delete tc;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include "bitReader.h"

#define LOAD8BYTESDATA_BE(x) \
    (((uint64_t)((const uint8_t*)(x))[0] << 56) | \
     ((uint64_t)((const uint8_t*)(x))[1] << 48) | \
     ((uint64_t)((const uint8_t*)(x))[2] << 40) | \
     ((uint64_t)((const uint8_t*)(x))[3] << 32) | \
     ((uint64_t)((const uint8_t*)(x))[4] << 24) | \
     ((uint64_t)((const uint8_t*)(x))[5] << 16) | \
     ((uint64_t)((const uint8_t*)(x))[6] <<  8) | \
     ((uint64_t)((const uint8_t*)(x))[7]))

namespace YamiParser {

const uint32_t BitReader::CACHEBYTES = sizeof(unsigned long int);

BitReader::BitReader(const uint8_t* pdata, uint32_t size)
    : m_stream(pdata)
    , m_size(size)
    , m_cache(0)
    , m_loadBytes(0)
    , m_bitsInCache(0)
{
    assert(pdata && size);
}

void BitReader::loadDataToCache(uint32_t nbytes)
{
    unsigned long int tmp = 0;
    const uint8_t* pStart = m_stream + m_loadBytes;

    if (nbytes == 8)
        tmp = LOAD8BYTESDATA_BE(pStart);
    else {
        for (uint32_t i = 0; i < nbytes; i++) {
            tmp <<= 8;
            tmp |= pStart[i];
        }
    }

    m_cache = tmp;
    m_loadBytes += nbytes;
    m_bitsInCache = nbytes << 3;
}

inline void BitReader::reload()
{
    assert(m_size >= m_loadBytes);
    uint32_t remainingBytes = m_size - m_loadBytes;
    if (remainingBytes > 0)
        loadDataToCache(std::min(remainingBytes, CACHEBYTES));
}

inline uint32_t BitReader::extractBitsFromCache(uint32_t nbits)
{
    if (!nbits)
        return 0;
    uint32_t tmp = 0;
    tmp = m_cache << ((CACHEBYTES << 3) - m_bitsInCache) >> ((CACHEBYTES << 3) - nbits);
    m_bitsInCache -= nbits;
    return tmp;
}

bool BitReader::read(uint32_t& v, uint32_t nbits)
{
    assert(nbits <= (CACHEBYTES << 3));

    if (nbits <= m_bitsInCache) {
        v = extractBitsFromCache(nbits);
        return true;
    }
    /*not enough bits, need to save remaining bits
      in current cache and then reload more bits*/
    uint32_t toBeReadBits = nbits - m_bitsInCache;
    uint32_t tmp = extractBitsFromCache(m_bitsInCache);
    reload();
    if (toBeReadBits > m_bitsInCache)
        return false;
    v = tmp << toBeReadBits | extractBitsFromCache(toBeReadBits);
    return true;
}

uint32_t BitReader::read(uint32_t nbits)
{
    uint32_t res;
    if (read(res, nbits))
        return res;
    return 0;
}

bool BitReader::skip(uint32_t nbits)
{
    uint32_t tmp;
    uint32_t size = sizeof(tmp) << 3;
    while (nbits > size) {
        if (!readT(tmp))
            return false;
        nbits -= size;
    }
    if (!read(tmp, nbits))
        return false;
    return true;
}

uint32_t BitReader::peek(uint32_t nbits) const
{
    BitReader tmp(*this);

    return tmp.read(nbits);
}

} /*namespace YamiParser*/
<commit_msg>BitReader: accept 0 size for byte stream, this fix previous unit test fail<commit_after>/*
 * Copyright 2016 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include "bitReader.h"

#define LOAD8BYTESDATA_BE(x) \
    (((uint64_t)((const uint8_t*)(x))[0] << 56) | \
     ((uint64_t)((const uint8_t*)(x))[1] << 48) | \
     ((uint64_t)((const uint8_t*)(x))[2] << 40) | \
     ((uint64_t)((const uint8_t*)(x))[3] << 32) | \
     ((uint64_t)((const uint8_t*)(x))[4] << 24) | \
     ((uint64_t)((const uint8_t*)(x))[5] << 16) | \
     ((uint64_t)((const uint8_t*)(x))[6] <<  8) | \
     ((uint64_t)((const uint8_t*)(x))[7]))

namespace YamiParser {

const uint32_t BitReader::CACHEBYTES = sizeof(unsigned long int);

BitReader::BitReader(const uint8_t* pdata, uint32_t size)
    : m_stream(pdata)
    , m_size(size)
    , m_cache(0)
    , m_loadBytes(0)
    , m_bitsInCache(0)
{
    if (size)
        assert(pdata);
}

void BitReader::loadDataToCache(uint32_t nbytes)
{
    unsigned long int tmp = 0;
    const uint8_t* pStart = m_stream + m_loadBytes;

    if (nbytes == 8)
        tmp = LOAD8BYTESDATA_BE(pStart);
    else {
        for (uint32_t i = 0; i < nbytes; i++) {
            tmp <<= 8;
            tmp |= pStart[i];
        }
    }

    m_cache = tmp;
    m_loadBytes += nbytes;
    m_bitsInCache = nbytes << 3;
}

inline void BitReader::reload()
{
    assert(m_size >= m_loadBytes);
    uint32_t remainingBytes = m_size - m_loadBytes;
    if (remainingBytes > 0)
        loadDataToCache(std::min(remainingBytes, CACHEBYTES));
}

inline uint32_t BitReader::extractBitsFromCache(uint32_t nbits)
{
    if (!nbits)
        return 0;
    uint32_t tmp = 0;
    tmp = m_cache << ((CACHEBYTES << 3) - m_bitsInCache) >> ((CACHEBYTES << 3) - nbits);
    m_bitsInCache -= nbits;
    return tmp;
}

bool BitReader::read(uint32_t& v, uint32_t nbits)
{
    assert(nbits <= (CACHEBYTES << 3));

    if (nbits <= m_bitsInCache) {
        v = extractBitsFromCache(nbits);
        return true;
    }
    /*not enough bits, need to save remaining bits
      in current cache and then reload more bits*/
    uint32_t toBeReadBits = nbits - m_bitsInCache;
    uint32_t tmp = extractBitsFromCache(m_bitsInCache);
    reload();
    if (toBeReadBits > m_bitsInCache)
        return false;
    v = tmp << toBeReadBits | extractBitsFromCache(toBeReadBits);
    return true;
}

uint32_t BitReader::read(uint32_t nbits)
{
    uint32_t res;
    if (read(res, nbits))
        return res;
    return 0;
}

bool BitReader::skip(uint32_t nbits)
{
    uint32_t tmp;
    uint32_t size = sizeof(tmp) << 3;
    while (nbits > size) {
        if (!readT(tmp))
            return false;
        nbits -= size;
    }
    if (!read(tmp, nbits))
        return false;
    return true;
}

uint32_t BitReader::peek(uint32_t nbits) const
{
    BitReader tmp(*this);

    return tmp.read(nbits);
}

} /*namespace YamiParser*/
<|endoftext|>


<commit_before>// Copyright 2014 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 "config.h"
#include "modules/serviceworkers/CacheStorage.h"

#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h"
#include "core/dom/DOMException.h"
#include "modules/serviceworkers/Cache.h"
#include "public/platform/WebServiceWorkerCacheError.h"
#include "public/platform/WebServiceWorkerCacheStorage.h"

namespace blink {

namespace {

PassRefPtrWillBeRawPtr<DOMException> createNoImplementationException()
{
    return DOMException::create(NotSupportedError, "No CacheStorage implementation provided.");
}

// FIXME: Consider using CallbackPromiseAdapter.
class CacheStorageCallbacks : public WebServiceWorkerCacheStorage::CacheStorageCallbacks {
    WTF_MAKE_NONCOPYABLE(CacheStorageCallbacks);
public:
    explicit CacheStorageCallbacks(PassRefPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) { }
    virtual ~CacheStorageCallbacks() { }

    virtual void onSuccess() OVERRIDE
    {
        m_resolver->resolve(true);
        m_resolver.clear();
    }

    virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
    {
        if (*reason == WebServiceWorkerCacheErrorNotFound)
            m_resolver->resolve(false);
        else
            m_resolver->resolve(Cache::domExceptionForCacheError(*reason));
        m_resolver.clear();
    }

private:
    RefPtr<ScriptPromiseResolver> m_resolver;
};

// FIXME: Consider using CallbackPromiseAdapter.
class CacheStorageWithCacheCallbacks : public WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks {
    WTF_MAKE_NONCOPYABLE(CacheStorageWithCacheCallbacks);
public:
    explicit CacheStorageWithCacheCallbacks(PassRefPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) { }
    virtual ~CacheStorageWithCacheCallbacks() { }

    virtual void onSuccess(WebServiceWorkerCache* cache) OVERRIDE
    {
        m_resolver->resolve(Cache::fromWebServiceWorkerCache(cache));
        m_resolver.clear();
    }

    virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
    {
        if (*reason == WebServiceWorkerCacheErrorNotFound)
            m_resolver->resolve();
        else
            m_resolver->resolve(Cache::domExceptionForCacheError(*reason));
        m_resolver.clear();
    }

private:
    RefPtr<ScriptPromiseResolver> m_resolver;
};

// FIXME: Consider using CallbackPromiseAdapter.
class CacheStorageKeysCallbacks : public WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks {
    WTF_MAKE_NONCOPYABLE(CacheStorageKeysCallbacks);
public:
    explicit CacheStorageKeysCallbacks(PassRefPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) { }
    virtual ~CacheStorageKeysCallbacks() { }

    virtual void onSuccess(WebVector<WebString>* keys) OVERRIDE
    {
        Vector<String> wtfKeys;
        for (size_t i = 0; i < keys->size(); ++i)
            wtfKeys.append((*keys)[i]);
        m_resolver->resolve(wtfKeys);
        m_resolver.clear();
    }

    virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
    {
        m_resolver->reject(Cache::domExceptionForCacheError(*reason));
        m_resolver.clear();
    }

private:
    RefPtr<ScriptPromiseResolver> m_resolver;
};

}

PassRefPtrWillBeRawPtr<CacheStorage> CacheStorage::create(WebServiceWorkerCacheStorage* webCacheStorage)
{
    return adoptRefWillBeNoop(new CacheStorage(webCacheStorage));
}

ScriptPromise CacheStorage::get(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchGet(new CacheStorageWithCacheCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::has(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchHas(new CacheStorageCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::createFunction(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchCreate(new CacheStorageWithCacheCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::deleteFunction(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchDelete(new CacheStorageCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::keys(ScriptState* scriptState)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchKeys(new CacheStorageKeysCallbacks(resolver));
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

CacheStorage::CacheStorage(WebServiceWorkerCacheStorage* webCacheStorage) : m_webCacheStorage(webCacheStorage)
{
    ScriptWrappable::init(this);
}

} // namespace blink
<commit_msg>Service Workers: CacheStorage should reject on error, not resolve<commit_after>// Copyright 2014 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 "config.h"
#include "modules/serviceworkers/CacheStorage.h"

#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h"
#include "core/dom/DOMException.h"
#include "modules/serviceworkers/Cache.h"
#include "public/platform/WebServiceWorkerCacheError.h"
#include "public/platform/WebServiceWorkerCacheStorage.h"

namespace blink {

namespace {

PassRefPtrWillBeRawPtr<DOMException> createNoImplementationException()
{
    return DOMException::create(NotSupportedError, "No CacheStorage implementation provided.");
}

// FIXME: Consider using CallbackPromiseAdapter.
class CacheStorageCallbacks : public WebServiceWorkerCacheStorage::CacheStorageCallbacks {
    WTF_MAKE_NONCOPYABLE(CacheStorageCallbacks);
public:
    explicit CacheStorageCallbacks(PassRefPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) { }
    virtual ~CacheStorageCallbacks() { }

    virtual void onSuccess() OVERRIDE
    {
        m_resolver->resolve(true);
        m_resolver.clear();
    }

    virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
    {
        if (*reason == WebServiceWorkerCacheErrorNotFound)
            m_resolver->resolve(false);
        else
            m_resolver->reject(Cache::domExceptionForCacheError(*reason));
        m_resolver.clear();
    }

private:
    RefPtr<ScriptPromiseResolver> m_resolver;
};

// FIXME: Consider using CallbackPromiseAdapter.
class CacheStorageWithCacheCallbacks : public WebServiceWorkerCacheStorage::CacheStorageWithCacheCallbacks {
    WTF_MAKE_NONCOPYABLE(CacheStorageWithCacheCallbacks);
public:
    explicit CacheStorageWithCacheCallbacks(PassRefPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) { }
    virtual ~CacheStorageWithCacheCallbacks() { }

    virtual void onSuccess(WebServiceWorkerCache* cache) OVERRIDE
    {
        m_resolver->resolve(Cache::fromWebServiceWorkerCache(cache));
        m_resolver.clear();
    }

    virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
    {
        if (*reason == WebServiceWorkerCacheErrorNotFound)
            m_resolver->resolve();
        else
            m_resolver->reject(Cache::domExceptionForCacheError(*reason));
        m_resolver.clear();
    }

private:
    RefPtr<ScriptPromiseResolver> m_resolver;
};

// FIXME: Consider using CallbackPromiseAdapter.
class CacheStorageKeysCallbacks : public WebServiceWorkerCacheStorage::CacheStorageKeysCallbacks {
    WTF_MAKE_NONCOPYABLE(CacheStorageKeysCallbacks);
public:
    explicit CacheStorageKeysCallbacks(PassRefPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) { }
    virtual ~CacheStorageKeysCallbacks() { }

    virtual void onSuccess(WebVector<WebString>* keys) OVERRIDE
    {
        Vector<String> wtfKeys;
        for (size_t i = 0; i < keys->size(); ++i)
            wtfKeys.append((*keys)[i]);
        m_resolver->resolve(wtfKeys);
        m_resolver.clear();
    }

    virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
    {
        m_resolver->reject(Cache::domExceptionForCacheError(*reason));
        m_resolver.clear();
    }

private:
    RefPtr<ScriptPromiseResolver> m_resolver;
};

}

PassRefPtrWillBeRawPtr<CacheStorage> CacheStorage::create(WebServiceWorkerCacheStorage* webCacheStorage)
{
    return adoptRefWillBeNoop(new CacheStorage(webCacheStorage));
}

ScriptPromise CacheStorage::get(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchGet(new CacheStorageWithCacheCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::has(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchHas(new CacheStorageCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::createFunction(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchCreate(new CacheStorageWithCacheCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::deleteFunction(ScriptState* scriptState, const String& cacheName)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchDelete(new CacheStorageCallbacks(resolver), cacheName);
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

ScriptPromise CacheStorage::keys(ScriptState* scriptState)
{
    RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    const ScriptPromise promise = resolver->promise();

    if (m_webCacheStorage)
        m_webCacheStorage->dispatchKeys(new CacheStorageKeysCallbacks(resolver));
    else
        resolver->reject(createNoImplementationException());

    return promise;
}

CacheStorage::CacheStorage(WebServiceWorkerCacheStorage* webCacheStorage) : m_webCacheStorage(webCacheStorage)
{
    ScriptWrappable::init(this);
}

} // namespace blink
<|endoftext|>