<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Rice University
*  All rights reserved.
*
*  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.
*   * Neither the name of the Rice University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  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 OWNER 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.
*********************************************************************/

/* Author: Ioan Sucan */

#include "ompl/base/StateAllocator.h"
#include "ompl/util/Exception.h"
#include <boost/thread.hpp>
#include <stack>
#include <list>
#include <map>

/// @cond IGNORE
namespace ompl
{
    namespace base
    {

        // This class corresponds to an instance of a StateAllocator. It gets deleted only after the
        // StateAllocator is deleted and all threads that use this instance have terminated.
        // This ensures that all stacks of states will be cleared.
        class AllocatorStacks
        {
        public:
            AllocatorStacks(const StateManifoldPtr &manifold) : manifold_(manifold)
            {
            }

            ~AllocatorStacks(void)
            {
                freeMemory();
            }

            std::stack<State*>* getStack(void)
            {
                boost::mutex::scoped_lock lock(lock_);
                if (avail_.empty())
                {
                    std::stack<State*> *s = new std::stack<State*>();
                    inuse_.push_back(s);
                    return s;
                }

                std::list< std::stack<State*>* >::iterator pos = avail_.begin();
                for (std::list< std::stack<State*>* >::iterator it = ++avail_.begin() ; it != avail_.end() ; ++it)
                    if ((*pos)->size() < (*it)->size())
                        pos = it;
                std::stack<State*> *s = *pos;
                avail_.erase(pos);
                inuse_.push_back(s);
                return s;
            }

            void returnStack(std::stack<State*> *s)
            {
                boost::mutex::scoped_lock lock(lock_);
                std::list< std::stack<State*>* >::iterator pos = std::find(inuse_.begin(), inuse_.end(), s);
                if (pos == inuse_.end())
                    throw Exception("Returning stack that was not in use. This should not happen");
                inuse_.erase(pos);
                avail_.push_back(s);
            }

            void clearAvailStacks(void)
            {
                boost::mutex::scoped_lock lock(lock_);
                for (std::list< std::stack<State*>* >::iterator it = avail_.begin() ; it != avail_.end() ; ++it)
                {
                    clearStack(**it);
                    delete *it;
                }
                avail_.clear();
            }

            std::pair<std::size_t,std::size_t> size(void)
            {
                std::size_t sz1 = 0;
                std::size_t sz2 = 0;
                boost::mutex::scoped_lock lock(lock_);
                for (std::list< std::stack<State*>* >::iterator it = avail_.begin() ; it != avail_.end() ; ++it)
                    sz1 += (*it)->size();
                for (std::list< std::stack<State*>* >::iterator it = inuse_.begin() ; it != inuse_.end() ; ++it)
                    sz2 += (*it)->size();
                return std::make_pair(sz1, sz2);
            }

        private:

            void clearStack(std::stack<State*> &s) const
            {
                while (!s.empty())
                {
                    manifold_->freeState(s.top());
                    s.pop();
                }
            }

            void freeMemory(void)
            {
                clearAvailStacks();
                if (!inuse_.empty())
                    throw Exception("Stack of states to be freed is in use by a thread. This should not happen.");
            }

            StateManifoldPtr                 manifold_;
            std::list< std::stack<State*>* > inuse_;
            std::list< std::stack<State*>* > avail_;
            boost::mutex                     lock_;
        };

        // this class gets allocated by each thread. it holds a shared pointer to the instance of AllocatorStacks
        // associated to the state allocator. Even if the StateAllocator has been deleted, the AllocatorStacks will exist
        // and this instance will be able to return its stack whenever the thread terminates
        class ThreadStorage
        {
        public:

            ThreadStorage(const boost::shared_ptr<AllocatorStacks> &availableStacks) : astacks(availableStacks)
            {
                stack = astacks->getStack();
            }

            ~ThreadStorage(void)
            {
                astacks->returnStack(stack);
            }

            boost::shared_ptr<AllocatorStacks>  astacks;
            std::stack<base::State*>           *stack;
        };

        // this object is created for every instance of StateAllocator and casted as void*
        // to avoid having to include too many header files in the .h file
        // this class is allocated by the constructor of StateAllocator and freed by the destructor.
        class StateAllocatorData
        {
        public:
            StateAllocatorData(const StateManifoldPtr &manifold) : astacks(new AllocatorStacks(manifold))
            {
            }

            boost::shared_ptr<AllocatorStacks>        astacks;
            boost::thread_specific_ptr<ThreadStorage> ts;
        };
    }
}

#define CDATA reinterpret_cast<StateAllocatorData*>(data_)

/// @endcond

ompl::base::StateAllocator::StateAllocator(const StateManifoldPtr &manifold) : manifold_(manifold)
{
    data_ = new StateAllocatorData(manifold);
}

ompl::base::StateAllocator::~StateAllocator(void)
{
    delete CDATA;
}

ompl::base::State* ompl::base::StateAllocator::allocState(void) const
{
    if (!CDATA->ts.get())
        CDATA->ts.reset(new ThreadStorage(CDATA->astacks));

    if (!CDATA->ts->stack->empty())
    {
        State *result = CDATA->ts->stack->top();
        CDATA->ts->stack->pop();
        return result;
    }

    return manifold_->allocState();
}

void ompl::base::StateAllocator::freeState(State *state) const
{
    if (!CDATA->ts.get())
        CDATA->ts.reset(new ThreadStorage(CDATA->astacks));
    CDATA->ts->stack->push(state);
}

std::size_t ompl::base::StateAllocator::sizeTotal(void) const
{
    std::pair<std::size_t, std::size_t> s = CDATA->astacks->size();
    return s.first + s.second;
}

std::size_t ompl::base::StateAllocator::sizeAvailable(void) const
{
    std::pair<std::size_t, std::size_t> s = CDATA->astacks->size();
    return s.first;
}

std::size_t ompl::base::StateAllocator::sizeInUse(void) const
{
    std::pair<std::size_t, std::size_t> s = CDATA->astacks->size();
    return s.second;
}

void ompl::base::StateAllocator::clear(void)
{
    CDATA->ts.reset();
    CDATA->astacks->clearAvailStacks();
}
<commit_msg>calling clear() in destructor; this should not make a difference in terms of correctness -- only clearing some of the memory earlier on<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Rice University
*  All rights reserved.
*
*  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.
*   * Neither the name of the Rice University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  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 OWNER 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.
*********************************************************************/

/* Author: Ioan Sucan */

#include "ompl/base/StateAllocator.h"
#include "ompl/util/Exception.h"
#include <boost/thread.hpp>
#include <stack>
#include <list>
#include <map>

/// @cond IGNORE
namespace ompl
{
    namespace base
    {

        // This class corresponds to an instance of a StateAllocator. It gets deleted only after the
        // StateAllocator is deleted and all threads that use this instance have terminated.
        // This ensures that all stacks of states will be cleared.
        class AllocatorStacks
        {
        public:
            AllocatorStacks(const StateManifoldPtr &manifold) : manifold_(manifold)
            {
            }

            ~AllocatorStacks(void)
            {
                freeMemory();
            }

            std::stack<State*>* getStack(void)
            {
                boost::mutex::scoped_lock lock(lock_);
                if (avail_.empty())
                {
                    std::stack<State*> *s = new std::stack<State*>();
                    inuse_.push_back(s);
                    return s;
                }

                std::list< std::stack<State*>* >::iterator pos = avail_.begin();
                for (std::list< std::stack<State*>* >::iterator it = ++avail_.begin() ; it != avail_.end() ; ++it)
                    if ((*pos)->size() < (*it)->size())
                        pos = it;
                std::stack<State*> *s = *pos;
                avail_.erase(pos);
                inuse_.push_back(s);
                return s;
            }

            void returnStack(std::stack<State*> *s)
            {
                boost::mutex::scoped_lock lock(lock_);
                std::list< std::stack<State*>* >::iterator pos = std::find(inuse_.begin(), inuse_.end(), s);
                if (pos == inuse_.end())
                    throw Exception("Returning stack that was not in use. This should not happen");
                inuse_.erase(pos);
                avail_.push_back(s);
            }

            void clearAvailStacks(void)
            {
                boost::mutex::scoped_lock lock(lock_);
                for (std::list< std::stack<State*>* >::iterator it = avail_.begin() ; it != avail_.end() ; ++it)
                {
                    clearStack(**it);
                    delete *it;
                }
                avail_.clear();
            }

            std::pair<std::size_t,std::size_t> size(void)
            {
                std::size_t sz1 = 0;
                std::size_t sz2 = 0;
                boost::mutex::scoped_lock lock(lock_);
                for (std::list< std::stack<State*>* >::iterator it = avail_.begin() ; it != avail_.end() ; ++it)
                    sz1 += (*it)->size();
                for (std::list< std::stack<State*>* >::iterator it = inuse_.begin() ; it != inuse_.end() ; ++it)
                    sz2 += (*it)->size();
                return std::make_pair(sz1, sz2);
            }

        private:

            void clearStack(std::stack<State*> &s) const
            {
                while (!s.empty())
                {
                    manifold_->freeState(s.top());
                    s.pop();
                }
            }

            void freeMemory(void)
            {
                clearAvailStacks();
                if (!inuse_.empty())
                    throw Exception("Stack of states to be freed is in use by a thread. This should not happen.");
            }

            StateManifoldPtr                 manifold_;
            std::list< std::stack<State*>* > inuse_;
            std::list< std::stack<State*>* > avail_;
            boost::mutex                     lock_;
        };

        // this class gets allocated by each thread. it holds a shared pointer to the instance of AllocatorStacks
        // associated to the state allocator. Even if the StateAllocator has been deleted, the AllocatorStacks will exist
        // and this instance will be able to return its stack whenever the thread terminates
        class ThreadStorage
        {
        public:

            ThreadStorage(const boost::shared_ptr<AllocatorStacks> &availableStacks) : astacks(availableStacks)
            {
                stack = astacks->getStack();
            }

            ~ThreadStorage(void)
            {
                astacks->returnStack(stack);
            }

            boost::shared_ptr<AllocatorStacks>  astacks;
            std::stack<base::State*>           *stack;
        };

        // this object is created for every instance of StateAllocator and casted as void*
        // to avoid having to include too many header files in the .h file
        // this class is allocated by the constructor of StateAllocator and freed by the destructor.
        class StateAllocatorData
        {
        public:
            StateAllocatorData(const StateManifoldPtr &manifold) : astacks(new AllocatorStacks(manifold))
            {
            }

            boost::shared_ptr<AllocatorStacks>        astacks;
            boost::thread_specific_ptr<ThreadStorage> ts;
        };
    }
}

#define CDATA reinterpret_cast<StateAllocatorData*>(data_)

/// @endcond

ompl::base::StateAllocator::StateAllocator(const StateManifoldPtr &manifold) : manifold_(manifold)
{
    data_ = new StateAllocatorData(manifold);
}

ompl::base::StateAllocator::~StateAllocator(void)
{
    clear();
    delete CDATA;
}

ompl::base::State* ompl::base::StateAllocator::allocState(void) const
{
    if (!CDATA->ts.get())
        CDATA->ts.reset(new ThreadStorage(CDATA->astacks));

    if (!CDATA->ts->stack->empty())
    {
        State *result = CDATA->ts->stack->top();
        CDATA->ts->stack->pop();
        return result;
    }

    return manifold_->allocState();
}

void ompl::base::StateAllocator::freeState(State *state) const
{
    if (!CDATA->ts.get())
        CDATA->ts.reset(new ThreadStorage(CDATA->astacks));
    CDATA->ts->stack->push(state);
}

std::size_t ompl::base::StateAllocator::sizeTotal(void) const
{
    std::pair<std::size_t, std::size_t> s = CDATA->astacks->size();
    return s.first + s.second;
}

std::size_t ompl::base::StateAllocator::sizeAvailable(void) const
{
    std::pair<std::size_t, std::size_t> s = CDATA->astacks->size();
    return s.first;
}

std::size_t ompl::base::StateAllocator::sizeInUse(void) const
{
    std::pair<std::size_t, std::size_t> s = CDATA->astacks->size();
    return s.second;
}

void ompl::base::StateAllocator::clear(void)
{
    CDATA->ts.reset();
    CDATA->astacks->clearAvailStacks();
}
<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of DO++, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <gtest/gtest.h>
#include <DO/Defines.hpp>

using namespace std;

TEST(DO_Core_Test, definesTest)
{
  cout << "DO++ version: " << DO_VERSION << endl;
  EXPECT_EQ(string(DO_VERSION), "1.0.0");

  cout << "string source path: " << endl << srcPath("") << endl << endl;
  EXPECT_TRUE( string(srcPath("")).find("test/Core") != string::npos );
}

//namespace DO { namespace Dev {
//
//  namespace ColorSpace {
//    struct RGB
//    { enum Channels { R = 0, G=1, B=2, NumChannels=3 }; };
//    struct RGBA
//    { enum Channels { R = 0, G=1, B=2, A=3, NumChannels=4 }; };
//    struct HSV
//    { enum Channels { H = 0, S=1, V=2, NumChannels=3 }; };
//    struct HSL
//    { enum Channels { H = 0, S=1, L=2, NumChannels=3 }; };
//    struct YUV
//    { enum Channels { Y = 0, U=1, V=2, NumChannels=3 }; };
//    struct CMYK
//    { enum Channels { C = 0, M=1, Y=2, K=3, NumChannels=4 }; };
//    struct CIELab
//    { enum Channels { L = 0, a=1, b=2, NumChannels=3 }; };
//    struct CIEXyz
//    { enum Channels { X=0, Y=1, Z=2, NumChannels=3 }; };
//  }
//
//  namespace ColorLayout {
//    /*struct R {}; struct G {}; struct B {}; struct A {};
//    struct L {}; struct a {}; struct b {};
//    struct Y {}; struct U {}; struct V {};
//    struct X {}; struct Y {}; struct Z {};
//    struct C {}; struct M {}; struct Y {}; struct K {};*/
//    struct RGB { enum Order { C0=0, C1=1, C2=2 }; };
//    struct BGR { enum Order { C0=2, C1=1, C2=0 }; };
//    struct RGBA { enum Order { C0=0, C1=1, C2=2, C3=3 }; };
//    struct ARGB { enum Order { C0=1, C1=2, C2=3, C3=0 }; };
//    struct ABGR { enum Order { C0=3, C1=2, C2=1, C3=0 }; };
//  }
//
//  template <int N1, int N2, int N3>
//  struct PackedFormat { enum { Bits1=N1, Bits2=N2, Bits3=N3} };
//
//  template <int N1, int N2, int N3, int N4>
//  struct PackedFormat { enum { Bits1=N1, Bits2=N2, Bits3=N3, Bits4=N4 } };
//
//  template <typename T_, typename ColorSpace_, typename ColorLayout_>
//  class Pixel
//  {
//  public:
//    typedef T_ T;
//    typedef ColorSpace_ ColorSpace;
//    typedef ColorLayout_ ColorLayout;
//    typedef int ChannelType;
//    T val;
//
//    template<typename C>
//    int get(ChannelType channelValue);
//
//    template<typename C>
//    int set(ChannelType channelValue);
//  };
//
//} /* namespace Dev */
//} /* namespace DO */
//
//TEST(DO_Core_Test, pixelTest)
//{
//  using namespace DO::Dev;
//  ASSERT_EQ(sizeof(Pixel<char>), sizeof(char));
//  ASSERT_EQ(sizeof(Pixel<int>), sizeof(int));
//  ASSERT_EQ(sizeof(Pixel<Vector3d>), sizeof(Vector3d));
//}

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}<commit_msg>Silence `Core_Defines` test.<commit_after>// ========================================================================== //
// This file is part of DO++, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <gtest/gtest.h>
#include <DO/Defines.hpp>

using namespace std;

TEST(DO_Core_Test, definesTest)
{
  EXPECT_EQ(string(DO_VERSION), "1.0.0");
  EXPECT_TRUE( string(srcPath("")).find("test/Core") != string::npos );
}

//namespace DO { namespace Dev {
//
//  namespace ColorSpace {
//    struct RGB
//    { enum Channels { R = 0, G=1, B=2, NumChannels=3 }; };
//    struct RGBA
//    { enum Channels { R = 0, G=1, B=2, A=3, NumChannels=4 }; };
//    struct HSV
//    { enum Channels { H = 0, S=1, V=2, NumChannels=3 }; };
//    struct HSL
//    { enum Channels { H = 0, S=1, L=2, NumChannels=3 }; };
//    struct YUV
//    { enum Channels { Y = 0, U=1, V=2, NumChannels=3 }; };
//    struct CMYK
//    { enum Channels { C = 0, M=1, Y=2, K=3, NumChannels=4 }; };
//    struct CIELab
//    { enum Channels { L = 0, a=1, b=2, NumChannels=3 }; };
//    struct CIEXyz
//    { enum Channels { X=0, Y=1, Z=2, NumChannels=3 }; };
//  }
//
//  namespace ColorLayout {
//    /*struct R {}; struct G {}; struct B {}; struct A {};
//    struct L {}; struct a {}; struct b {};
//    struct Y {}; struct U {}; struct V {};
//    struct X {}; struct Y {}; struct Z {};
//    struct C {}; struct M {}; struct Y {}; struct K {};*/
//    struct RGB { enum Order { C0=0, C1=1, C2=2 }; };
//    struct BGR { enum Order { C0=2, C1=1, C2=0 }; };
//    struct RGBA { enum Order { C0=0, C1=1, C2=2, C3=3 }; };
//    struct ARGB { enum Order { C0=1, C1=2, C2=3, C3=0 }; };
//    struct ABGR { enum Order { C0=3, C1=2, C2=1, C3=0 }; };
//  }
//
//  template <int N1, int N2, int N3>
//  struct PackedFormat { enum { Bits1=N1, Bits2=N2, Bits3=N3} };
//
//  template <int N1, int N2, int N3, int N4>
//  struct PackedFormat { enum { Bits1=N1, Bits2=N2, Bits3=N3, Bits4=N4 } };
//
//  template <typename T_, typename ColorSpace_, typename ColorLayout_>
//  class Pixel
//  {
//  public:
//    typedef T_ T;
//    typedef ColorSpace_ ColorSpace;
//    typedef ColorLayout_ ColorLayout;
//    typedef int ChannelType;
//    T val;
//
//    template<typename C>
//    int get(ChannelType channelValue);
//
//    template<typename C>
//    int set(ChannelType channelValue);
//  };
//
//} /* namespace Dev */
//} /* namespace DO */
//
//TEST(DO_Core_Test, pixelTest)
//{
//  using namespace DO::Dev;
//  ASSERT_EQ(sizeof(Pixel<char>), sizeof(char));
//  ASSERT_EQ(sizeof(Pixel<int>), sizeof(int));
//  ASSERT_EQ(sizeof(Pixel<Vector3d>), sizeof(Vector3d));
//}

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}<|endoftext|>


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

TEST(insertNodeWithKeyTest, LeftLeftHeavyCase1) {
    avl_tree<int> avlt;
    avlt.insertNodeWithKey(2);
    avlt.insertNodeWithKey(1);
    avlt.insertNodeWithKey(0);
    stringstream ss;
    avlt.printTree(ss);
    string expectedOutput =
        string("\t2\n") +
        string("1\n") +
        string("\t0\n");
    EXPECT_EQ(expectedOutput, ss.str());
}<commit_msg>Modify avl_tree_unittest:TEST(insertNodeWithKeyTest, LeftLeftHeavyCase1) Add avl_tree_unittest:TEST(insertNodeWithKeyTest, LeftLeftHeavyCase2) Add avl_tree_unittest:TEST(insertNodeWithKeyTest, LeftRightHeavyCase1) Add avl_tree_unittest:TEST(insertNodeWithKeyTest, LeftRightHeavyCase2)<commit_after>#include "../include/avl_tree.h"
#include "gtest/gtest.h"
#include <sstream>

TEST(insertNodeWithKeyTest, LeftLeftHeavyCase1) {
    avl_tree<int> avlt;
    avlt.insertNodeWithKey(2);
    avlt.insertNodeWithKey(1);
    avlt.insertNodeWithKey(0);
    stringstream ss;
    avlt.printTree(ss);
    string expectedOutput =
        string("\t2\n") +
        string("1\n") +
        string("\t0\n");
    EXPECT_EQ(ss.str(), expectedOutput);
    auto node2 = avlt.getNodeWithKey(2);
    auto node1 = avlt.getNodeWithKey(1);
    auto node0 = avlt.getNodeWithKey(0);
    // test parents
    EXPECT_EQ(node2->getParent(), node1);
    EXPECT_EQ(node1->getParent(), nullptr);
    EXPECT_EQ(node0->getParent(), node1);
    // test heights
    EXPECT_EQ(node2->getHeight(), 0);
    EXPECT_EQ(node1->getHeight(), 1);
    EXPECT_EQ(node0->getHeight(), 0);
}

TEST(insertNodeWithKeyTest, LeftLeftHeavyCase2) {
    avl_tree<int> avlt;
    avlt.insertNodeWithKey(4);
    avlt.insertNodeWithKey(2);
    avlt.insertNodeWithKey(5);
    avlt.insertNodeWithKey(1);
    avlt.insertNodeWithKey(3);
    avlt.insertNodeWithKey(0);
    stringstream ss;
    avlt.printTree(ss);
    string expectedOutput =
        string("\t\t5\n") +
        string("\t4\n") +
        string("\t\t3\n") +
        string("2\n") +
        string("\t1\n") +
        string("\t\t0\n");
    EXPECT_EQ(ss.str(), expectedOutput);
    auto node5 = avlt.getNodeWithKey(5);
    auto node4 = avlt.getNodeWithKey(4);
    auto node3 = avlt.getNodeWithKey(3);
    auto node2 = avlt.getNodeWithKey(2);
    auto node1 = avlt.getNodeWithKey(1);
    auto node0 = avlt.getNodeWithKey(0);
    // test parents
    EXPECT_EQ(node5->getParent(), node4);
    EXPECT_EQ(node4->getParent(), node2);
    EXPECT_EQ(node3->getParent(), node4);
    EXPECT_EQ(node2->getParent(), nullptr);
    EXPECT_EQ(node1->getParent(), node2);
    EXPECT_EQ(node0->getParent(), node1);
    // test heights
    EXPECT_EQ(node5->getHeight(), 0);
    EXPECT_EQ(node4->getHeight(), 1);
    EXPECT_EQ(node3->getHeight(), 0);
    EXPECT_EQ(node2->getHeight(), 2);
    EXPECT_EQ(node1->getHeight(), 1);
    EXPECT_EQ(node0->getHeight(), 0);
}

TEST(insertNodeWithKeyTest, LeftRightHeavyCase1) {
    avl_tree<int> avlt;
    avlt.insertNodeWithKey(2);
    avlt.insertNodeWithKey(0);
    avlt.insertNodeWithKey(1);
    stringstream ss;
    avlt.printTree(ss);
    string expectedOutput =
        string("\t2\n") +
        string("1\n") +
        string("\t0\n");
    EXPECT_EQ(ss.str(), expectedOutput);
    auto node2 = avlt.getNodeWithKey(2);
    auto node1 = avlt.getNodeWithKey(1);
    auto node0 = avlt.getNodeWithKey(0);
    // test parents
    EXPECT_EQ(node2->getParent(), node1);
    EXPECT_EQ(node1->getParent(), nullptr);
    EXPECT_EQ(node0->getParent(), node1);
    // test heights
    EXPECT_EQ(node2->getHeight(), 0);
    EXPECT_EQ(node1->getHeight(), 1);
    EXPECT_EQ(node0->getHeight(), 0);
}

TEST(insertNodeWithKeyTest, LeftRightHeavyCase2) {
    avl_tree<int> avlt;
    avlt.insertNodeWithKey(4);
    avlt.insertNodeWithKey(1);
    avlt.insertNodeWithKey(5);
    avlt.insertNodeWithKey(0);
    avlt.insertNodeWithKey(2);
    avlt.insertNodeWithKey(3);
    stringstream ss;
    avlt.printTree(ss);
    string expectedOutput =
        string("\t\t5\n") +
        string("\t4\n") +
        string("\t\t3\n") +
        string("2\n") +
        string("\t1\n") +
        string("\t\t0\n");
    EXPECT_EQ(ss.str(), expectedOutput);
    auto node5 = avlt.getNodeWithKey(5);
    auto node4 = avlt.getNodeWithKey(4);
    auto node3 = avlt.getNodeWithKey(3);
    auto node2 = avlt.getNodeWithKey(2);
    auto node1 = avlt.getNodeWithKey(1);
    auto node0 = avlt.getNodeWithKey(0);
    // test parents
    EXPECT_EQ(node5->getParent(), node4);
    EXPECT_EQ(node4->getParent(), node2);
    EXPECT_EQ(node3->getParent(), node4);
    EXPECT_EQ(node2->getParent(), nullptr);
    EXPECT_EQ(node1->getParent(), node2);
    EXPECT_EQ(node0->getParent(), node1);
    // test heights
    EXPECT_EQ(node5->getHeight(), 0);
    EXPECT_EQ(node4->getHeight(), 1);
    EXPECT_EQ(node3->getHeight(), 0);
    EXPECT_EQ(node2->getHeight(), 2);
    EXPECT_EQ(node1->getHeight(), 1);
    EXPECT_EQ(node0->getHeight(), 0);
}<|endoftext|>


<commit_before>#include "cvm.h"

#include "defaults_shared.h"

DabClass &DabVM::define_builtin_class(const std::string &name, dab_class_t class_index,
                                      dab_class_t superclass_index)
{
    DabClass klass;
    klass.index            = class_index;
    klass.name             = name;
    klass.builtin          = true;
    klass.superclass_index = superclass_index;
    classes[class_index]   = klass;
    return classes[class_index];
}

void DabVM::predefine_default_classes()
{
    fprintf(stderr, "vm: predefine default classes\n");

    define_builtin_class("Object", CLASS_OBJECT);
    define_builtin_class("String", CLASS_STRING);
    define_builtin_class("Fixnum", CLASS_FIXNUM);
    define_builtin_class("Boolean", CLASS_BOOLEAN);
    define_builtin_class("NilClass", CLASS_NILCLASS);
    define_builtin_class("Array", CLASS_ARRAY);
    define_builtin_class("Uint8", CLASS_UINT8, CLASS_FIXNUM);
    define_builtin_class("Uint16", CLASS_UINT16, CLASS_FIXNUM);
    define_builtin_class("Uint32", CLASS_UINT32, CLASS_FIXNUM);
    define_builtin_class("Uint64", CLASS_UINT64, CLASS_FIXNUM);
    define_builtin_class("Int8", CLASS_INT8, CLASS_FIXNUM);
    define_builtin_class("Int16", CLASS_INT16, CLASS_FIXNUM);
    define_builtin_class("Int32", CLASS_INT32, CLASS_FIXNUM);
    define_builtin_class("Int64", CLASS_INT64, CLASS_FIXNUM);
    define_builtin_class("Method", CLASS_METHOD);
    define_builtin_class("IntPtr", CLASS_INTPTR);
    define_builtin_class("ByteBuffer", CLASS_BYTEBUFFER);
    define_builtin_class("LiteralString", CLASS_LITERALSTRING, CLASS_STRING);
}

void DabVM::define_default_classes()
{
    fprintf(stderr, "vm: define default classes\n");

    auto &object_class = get_class(CLASS_OBJECT);
    object_class.add_static_reg_function("new", [this](DabValue self, std::vector<DabValue>) {
        auto arg = self;
        assert(arg.data.type == TYPE_CLASS);
        auto instance = arg.create_instance();
        cinstcall(instance, "__construct");
        return instance;
    });
    object_class.add_reg_function(
        "class", [](DabValue self, std::vector<DabValue>) { return self.get_class(); });
    object_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.print_value();
    });
    object_class.add_reg_function("__construct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("__destruct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("is", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        return arg0.is_a(arg1.get_class());
    });
    object_class.add_static_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.class_name();
    });
    object_class.add_static_reg_function("==", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_CLASS);
        assert(arg1.data.type == TYPE_CLASS);
        return DabValue(arg0.data.fixnum == arg1.data.fixnum);
    });

    auto &string_class = get_class(CLASS_STRING);
    string_class.add_reg_function("upcase", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto s = self.string();
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    });
    string_class.add_reg_function("length", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     s = self.string();
        DabValue ret(CLASS_INT32, (int)s.size());
        return ret;
    });
    string_class.add_reg_function("[]", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_FIXNUM);
        auto s   = self.string();
        auto n   = arg.data.fixnum;
        return DabValue(s.substr(n, 1));
    });
    string_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = $VM->cast(args[0], CLASS_STRING);
        auto s0   = arg0.string();
        auto s1   = arg1.string();
        return DabValue(s0 + s1);
    });
    string_class.add_static_reg_function("new", [](DabValue, std::vector<DabValue> args) {
        auto argc = args.size();
        assert(argc <= 2);
        DabValue ret_value;
        ret_value.data.type = TYPE_STRING;
        if (argc == 2)
        {
            auto        arg1   = $VM->cast(args[0], CLASS_BYTEBUFFER);
            auto        arg2   = $VM->cast(args[1], CLASS_FIXNUM);
            const auto &buffer = arg1.bytebuffer();
            const auto  length = arg2.data.fixnum;
            if (length)
            {
                ret_value.data.legacy_string = std::string((const char *)&buffer[0], length);
            }
        }
        else if (argc == 1)
        {
            ret_value.data.legacy_string = args[0].string();
        }
        return ret_value;
    });
    string_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self;
    });
    DAB_MEMBER_EQUALS_OPERATORS(string_class, CLASS_STRING, .string());
    DAB_MEMBER_COMPARE_OPERATORS(string_class, CLASS_STRING, .string());

    auto &fixnum_class = get_class(CLASS_FIXNUM);
    fixnum_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() <= 1);
        auto     klass = self;
        DabValue ret_value;
        ret_value.data.type   = TYPE_FIXNUM;
        ret_value.data.fixnum = 0;
        if (args.size() == 1)
        {
            auto arg = args[0];
            assert(arg.data.type == TYPE_FIXNUM);
            ret_value.data.fixnum = arg.data.fixnum;
        }
        return ret_value;
    });
    DAB_MEMBER_NUMERIC_OPERATORS(fixnum_class, CLASS_FIXNUM, uint64_t, .data.fixnum);

    define_default_classes_int();

    auto &intptr_class = get_class(CLASS_INTPTR);
    intptr_class.add_reg_function("fetch_int32", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     ptr   = self.data.intptr;
        auto     iptr  = (int32_t *)ptr;
        auto     value = *iptr;
        DabValue ret(CLASS_INT32, value);
        return ret;
    });

    auto &boolean_class = get_class(CLASS_BOOLEAN);
    DAB_MEMBER_EQUALS_OPERATORS(boolean_class, CLASS_BOOLEAN, .data.boolean);

    auto &array_class = get_class(CLASS_ARRAY);
    array_class.add_reg_function("count", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        return (uint64_t)self.array().size();
    });
    array_class.add_function("shift", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 1);
        assert(n_ret == 1);
        auto self = stack.pop_value();
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        if (a.size() == 0)
        {
            stack.push_value(nullptr);
        }
        else
        {
            auto ret = a[0];
            a.erase(a.begin());
            stack.push_value(ret);
        }
    });
    array_class.add_function("insert", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 2);
        assert(n_ret == 1);
        auto self = stack.pop_value();
        auto arg  = stack.pop_value();
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        a.push_back(arg);
        stack.push_value(nullptr);
    });
    array_class.add_function("[]", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 2);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            stack.push_value(nullptr);
        else
            stack.push_value(a[n]);
    });
    array_class.add_function("[]=", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 3);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg2 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
        {
            fprintf(stderr, "vm: index outside of array bounds.\n");
            exit(1);
        }
        else
        {
            a[n] = arg2;
            stack.push_value(nullptr);
        }
    });
    array_class.add_reg_function("join", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.array();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            auto val = cinstcall(a[i], "to_s");
            ret += val.string();
        }
        return ret;
    });
    array_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto inner = cinstcall(self, "join");
        return std::string("[" + inner.string() + "]");
    });
    array_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_ARRAY);
        return $VM->merge_arrays(self, arg);
    });

    auto &method_class = get_class(CLASS_METHOD);
    method_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return std::string("@method(" + self.string() + ")");
    });

    auto &bytebuffer_class = get_class(CLASS_BYTEBUFFER);
    bytebuffer_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto klass = self;
        assert(klass.data.type == TYPE_CLASS);

        auto instance = klass.create_instance();

        auto _size = $VM->cast(args[0], CLASS_FIXNUM);
        auto size  = _size.data.fixnum;
        instance.bytebuffer().resize(size);
        return instance;
    });
    bytebuffer_class.add_reg_function("[]", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            return DabValue(nullptr);
        else
            return DabValue(CLASS_UINT8, a[n]);
    });
    bytebuffer_class.add_reg_function("[]=", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 2);
        auto arg0 = self;
        auto arg1 = args[0];
        auto arg2 = args[1];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n >= 0 && n < (int64_t)a.size())
        {
            a[n] = $VM->cast(arg2, CLASS_UINT8).data.num_uint8;
        }
        return nullptr;
    });
    bytebuffer_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.bytebuffer();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            char string[32];
            sprintf(string, "%d", (int)a[i]);
            ret += string;
        }
        return "[" + ret + "]";
    });
}
<commit_msg>vm: registerify Array.shift<commit_after>#include "cvm.h"

#include "defaults_shared.h"

DabClass &DabVM::define_builtin_class(const std::string &name, dab_class_t class_index,
                                      dab_class_t superclass_index)
{
    DabClass klass;
    klass.index            = class_index;
    klass.name             = name;
    klass.builtin          = true;
    klass.superclass_index = superclass_index;
    classes[class_index]   = klass;
    return classes[class_index];
}

void DabVM::predefine_default_classes()
{
    fprintf(stderr, "vm: predefine default classes\n");

    define_builtin_class("Object", CLASS_OBJECT);
    define_builtin_class("String", CLASS_STRING);
    define_builtin_class("Fixnum", CLASS_FIXNUM);
    define_builtin_class("Boolean", CLASS_BOOLEAN);
    define_builtin_class("NilClass", CLASS_NILCLASS);
    define_builtin_class("Array", CLASS_ARRAY);
    define_builtin_class("Uint8", CLASS_UINT8, CLASS_FIXNUM);
    define_builtin_class("Uint16", CLASS_UINT16, CLASS_FIXNUM);
    define_builtin_class("Uint32", CLASS_UINT32, CLASS_FIXNUM);
    define_builtin_class("Uint64", CLASS_UINT64, CLASS_FIXNUM);
    define_builtin_class("Int8", CLASS_INT8, CLASS_FIXNUM);
    define_builtin_class("Int16", CLASS_INT16, CLASS_FIXNUM);
    define_builtin_class("Int32", CLASS_INT32, CLASS_FIXNUM);
    define_builtin_class("Int64", CLASS_INT64, CLASS_FIXNUM);
    define_builtin_class("Method", CLASS_METHOD);
    define_builtin_class("IntPtr", CLASS_INTPTR);
    define_builtin_class("ByteBuffer", CLASS_BYTEBUFFER);
    define_builtin_class("LiteralString", CLASS_LITERALSTRING, CLASS_STRING);
}

void DabVM::define_default_classes()
{
    fprintf(stderr, "vm: define default classes\n");

    auto &object_class = get_class(CLASS_OBJECT);
    object_class.add_static_reg_function("new", [this](DabValue self, std::vector<DabValue>) {
        auto arg = self;
        assert(arg.data.type == TYPE_CLASS);
        auto instance = arg.create_instance();
        cinstcall(instance, "__construct");
        return instance;
    });
    object_class.add_reg_function(
        "class", [](DabValue self, std::vector<DabValue>) { return self.get_class(); });
    object_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.print_value();
    });
    object_class.add_reg_function("__construct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("__destruct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("is", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        return arg0.is_a(arg1.get_class());
    });
    object_class.add_static_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.class_name();
    });
    object_class.add_static_reg_function("==", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_CLASS);
        assert(arg1.data.type == TYPE_CLASS);
        return DabValue(arg0.data.fixnum == arg1.data.fixnum);
    });

    auto &string_class = get_class(CLASS_STRING);
    string_class.add_reg_function("upcase", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto s = self.string();
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    });
    string_class.add_reg_function("length", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     s = self.string();
        DabValue ret(CLASS_INT32, (int)s.size());
        return ret;
    });
    string_class.add_reg_function("[]", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_FIXNUM);
        auto s   = self.string();
        auto n   = arg.data.fixnum;
        return DabValue(s.substr(n, 1));
    });
    string_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = $VM->cast(args[0], CLASS_STRING);
        auto s0   = arg0.string();
        auto s1   = arg1.string();
        return DabValue(s0 + s1);
    });
    string_class.add_static_reg_function("new", [](DabValue, std::vector<DabValue> args) {
        auto argc = args.size();
        assert(argc <= 2);
        DabValue ret_value;
        ret_value.data.type = TYPE_STRING;
        if (argc == 2)
        {
            auto        arg1   = $VM->cast(args[0], CLASS_BYTEBUFFER);
            auto        arg2   = $VM->cast(args[1], CLASS_FIXNUM);
            const auto &buffer = arg1.bytebuffer();
            const auto  length = arg2.data.fixnum;
            if (length)
            {
                ret_value.data.legacy_string = std::string((const char *)&buffer[0], length);
            }
        }
        else if (argc == 1)
        {
            ret_value.data.legacy_string = args[0].string();
        }
        return ret_value;
    });
    string_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self;
    });
    DAB_MEMBER_EQUALS_OPERATORS(string_class, CLASS_STRING, .string());
    DAB_MEMBER_COMPARE_OPERATORS(string_class, CLASS_STRING, .string());

    auto &fixnum_class = get_class(CLASS_FIXNUM);
    fixnum_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() <= 1);
        auto     klass = self;
        DabValue ret_value;
        ret_value.data.type   = TYPE_FIXNUM;
        ret_value.data.fixnum = 0;
        if (args.size() == 1)
        {
            auto arg = args[0];
            assert(arg.data.type == TYPE_FIXNUM);
            ret_value.data.fixnum = arg.data.fixnum;
        }
        return ret_value;
    });
    DAB_MEMBER_NUMERIC_OPERATORS(fixnum_class, CLASS_FIXNUM, uint64_t, .data.fixnum);

    define_default_classes_int();

    auto &intptr_class = get_class(CLASS_INTPTR);
    intptr_class.add_reg_function("fetch_int32", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     ptr   = self.data.intptr;
        auto     iptr  = (int32_t *)ptr;
        auto     value = *iptr;
        DabValue ret(CLASS_INT32, value);
        return ret;
    });

    auto &boolean_class = get_class(CLASS_BOOLEAN);
    DAB_MEMBER_EQUALS_OPERATORS(boolean_class, CLASS_BOOLEAN, .data.boolean);

    auto &array_class = get_class(CLASS_ARRAY);
    array_class.add_reg_function("count", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        return (uint64_t)self.array().size();
    });
    array_class.add_reg_function("shift", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        if (a.size() == 0)
        {
            return DabValue(nullptr);
        }
        else
        {
            auto ret = a[0];
            a.erase(a.begin());
            return ret;
        }
    });
    array_class.add_function("insert", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 2);
        assert(n_ret == 1);
        auto self = stack.pop_value();
        auto arg  = stack.pop_value();
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        a.push_back(arg);
        stack.push_value(nullptr);
    });
    array_class.add_function("[]", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 2);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            stack.push_value(nullptr);
        else
            stack.push_value(a[n]);
    });
    array_class.add_function("[]=", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 3);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg2 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
        {
            fprintf(stderr, "vm: index outside of array bounds.\n");
            exit(1);
        }
        else
        {
            a[n] = arg2;
            stack.push_value(nullptr);
        }
    });
    array_class.add_reg_function("join", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.array();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            auto val = cinstcall(a[i], "to_s");
            ret += val.string();
        }
        return ret;
    });
    array_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto inner = cinstcall(self, "join");
        return std::string("[" + inner.string() + "]");
    });
    array_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_ARRAY);
        return $VM->merge_arrays(self, arg);
    });

    auto &method_class = get_class(CLASS_METHOD);
    method_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return std::string("@method(" + self.string() + ")");
    });

    auto &bytebuffer_class = get_class(CLASS_BYTEBUFFER);
    bytebuffer_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto klass = self;
        assert(klass.data.type == TYPE_CLASS);

        auto instance = klass.create_instance();

        auto _size = $VM->cast(args[0], CLASS_FIXNUM);
        auto size  = _size.data.fixnum;
        instance.bytebuffer().resize(size);
        return instance;
    });
    bytebuffer_class.add_reg_function("[]", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            return DabValue(nullptr);
        else
            return DabValue(CLASS_UINT8, a[n]);
    });
    bytebuffer_class.add_reg_function("[]=", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 2);
        auto arg0 = self;
        auto arg1 = args[0];
        auto arg2 = args[1];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n >= 0 && n < (int64_t)a.size())
        {
            a[n] = $VM->cast(arg2, CLASS_UINT8).data.num_uint8;
        }
        return nullptr;
    });
    bytebuffer_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.bytebuffer();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            char string[32];
            sprintf(string, "%d", (int)a[i]);
            ret += string;
        }
        return "[" + ret + "]";
    });
}
<|endoftext|>


<commit_before>/*
 *
 * BytesReader
 * ledger-core
 *
 * Created by Pierre Pollastri on 14/09/2016.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Ledger
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include "BytesReader.h"
#include "../utils/endian.h"
#include <fmt/format.h>
#include <sstream>

namespace ledger {

    namespace core {

        BytesReader::BytesReader(const std::vector<uint8_t> &data, unsigned long offset, unsigned long length) {
            _bytes = data;
            _offset = offset;
            _length = length;
            _cursor = offset;
        }

        void BytesReader::seek(long offset, BytesReader::Seek origin) {
            unsigned long off = 0;
            switch (origin) {
                case Seek::CUR :
                    off = _cursor + offset;
                    break;
                case Seek::SET :
                    off = _offset;
                    break;
                case Seek::END :
                    off = _offset + _length + offset;
                    break;
            }
            if (off < _offset) {
                throw std::out_of_range(fmt::format("Offset [{}] is to low (minimum value is {})", off, _offset));
            } else if (off > (_offset + _length)) {
                throw std::out_of_range(fmt::format("Offset [{}] is to high (maximum value is {})", off, _offset + _length));
            }
            _cursor = off;
        }

        std::vector<uint8_t> BytesReader::read(unsigned long length) {
            std::vector<uint8_t> data(length);
            for (auto i = 0; i < length; i++) {
                data[i] = _bytes[_cursor];
                seek(1, Seek::CUR);
            }
            return data;
        }

        unsigned long BytesReader::getCursor() const {
            return _cursor - _offset;
        }

        bool BytesReader::hasNext() const {
            return available() != 0;
        }

        unsigned long BytesReader::available() const {
            return (_length + _offset) - _cursor;
        }

        std::string BytesReader::readString(unsigned long length) {
            std::string result(length, '0');
            auto index = 0UL;
            for (auto byte : read(length)) {
                result[index] = byte;
                index += 1;
            }
            return result;
        }

        uint8_t BytesReader::readNextByte() {
            uint8_t result = _bytes[_cursor];
            seek(1, Seek::CUR);
            return result;
        }

        std::string BytesReader::readNextString() {
            std::ostringstream oss;
            uint8_t byte;
            do {
                byte = readNextByte();
                if (byte != '\0')
                    oss << byte;
            } while (byte != '\0');
            return oss.str();
        }

        uint32_t BytesReader::readNextBeUint() {
            uint32_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                        ledger::core::endianness::Endianness::BIG,
                                                        ledger::core::endianness::getSystemEndianness());
            return result;
        }

        uint32_t BytesReader::readNextLeUint() {
            uint32_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                       ledger::core::endianness::Endianness::LITTLE,
                                                       ledger::core::endianness::getSystemEndianness());
            return result;
        }

        uint64_t BytesReader::readNextBeUlong() {
            uint64_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                       ledger::core::endianness::Endianness::BIG,
                                                       ledger::core::endianness::getSystemEndianness());
            return result;
        }

        uint64_t BytesReader::readNextLeUlong() {
            uint64_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                       ledger::core::endianness::Endianness::LITTLE,
                                                       ledger::core::endianness::getSystemEndianness());
            return result;
        }

        ledger::core::BigInt BytesReader::readNextBeBigInt(size_t bytes) {
            auto data = read(bytes);
            return BigInt(data.data(), data.size(), false);
        }

        ledger::core::BigInt BytesReader::readNextLeBigInt(size_t bytes) {
            auto data = read(bytes);
            std::reverse(data.begin(), data.end());
            return BigInt(data.data(), data.size(), false);
        }

        uint64_t BytesReader::readNextVarInt() {
            uint8_t size = readNextByte();
            switch (size) {
                case 0xFD:
                    size = 2;
                    break;
                case 0xFE:
                    size = 4;
                    break;
                case 0xFF:
                    size = 8;
                    break;
                default:
                    return size;
            }
            return readNextLeBigInt(size).toUint64();
        }

        std::string BytesReader::readNextVarString() {
            uint64_t length = readNextVarInt();
            return readString(length);
        }

        uint8_t BytesReader::peek() const {
            return _bytes[_cursor];
        }

    }
}<commit_msg>Fix std::reverse not found<commit_after>/*
 *
 * BytesReader
 * ledger-core
 *
 * Created by Pierre Pollastri on 14/09/2016.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Ledger
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include "BytesReader.h"
#include "../utils/endian.h"
#include <fmt/format.h>
#include <sstream>
#include <algorithm>

namespace ledger {

    namespace core {

        BytesReader::BytesReader(const std::vector<uint8_t> &data, unsigned long offset, unsigned long length) {
            _bytes = data;
            _offset = offset;
            _length = length;
            _cursor = offset;
        }

        void BytesReader::seek(long offset, BytesReader::Seek origin) {
            unsigned long off = 0;
            switch (origin) {
                case Seek::CUR :
                    off = _cursor + offset;
                    break;
                case Seek::SET :
                    off = _offset;
                    break;
                case Seek::END :
                    off = _offset + _length + offset;
                    break;
            }
            if (off < _offset) {
                throw std::out_of_range(fmt::format("Offset [{}] is to low (minimum value is {})", off, _offset));
            } else if (off > (_offset + _length)) {
                throw std::out_of_range(fmt::format("Offset [{}] is to high (maximum value is {})", off, _offset + _length));
            }
            _cursor = off;
        }

        std::vector<uint8_t> BytesReader::read(unsigned long length) {
            std::vector<uint8_t> data(length);
            for (auto i = 0; i < length; i++) {
                data[i] = _bytes[_cursor];
                seek(1, Seek::CUR);
            }
            return data;
        }

        unsigned long BytesReader::getCursor() const {
            return _cursor - _offset;
        }

        bool BytesReader::hasNext() const {
            return available() != 0;
        }

        unsigned long BytesReader::available() const {
            return (_length + _offset) - _cursor;
        }

        std::string BytesReader::readString(unsigned long length) {
            std::string result(length, '0');
            auto index = 0UL;
            for (auto byte : read(length)) {
                result[index] = byte;
                index += 1;
            }
            return result;
        }

        uint8_t BytesReader::readNextByte() {
            uint8_t result = _bytes[_cursor];
            seek(1, Seek::CUR);
            return result;
        }

        std::string BytesReader::readNextString() {
            std::ostringstream oss;
            uint8_t byte;
            do {
                byte = readNextByte();
                if (byte != '\0')
                    oss << byte;
            } while (byte != '\0');
            return oss.str();
        }

        uint32_t BytesReader::readNextBeUint() {
            uint32_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                        ledger::core::endianness::Endianness::BIG,
                                                        ledger::core::endianness::getSystemEndianness());
            return result;
        }

        uint32_t BytesReader::readNextLeUint() {
            uint32_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                       ledger::core::endianness::Endianness::LITTLE,
                                                       ledger::core::endianness::getSystemEndianness());
            return result;
        }

        uint64_t BytesReader::readNextBeUlong() {
            uint64_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                       ledger::core::endianness::Endianness::BIG,
                                                       ledger::core::endianness::getSystemEndianness());
            return result;
        }

        uint64_t BytesReader::readNextLeUlong() {
            uint64_t result;
            uint8_t* ptr = reinterpret_cast<uint8_t *>(&result);
            for (auto i = 0; i < sizeof(result); i++) {
                ptr[i] = readNextByte();
            }
            ledger::core::endianness::swapToEndianness(ptr, sizeof(result),
                                                       ledger::core::endianness::Endianness::LITTLE,
                                                       ledger::core::endianness::getSystemEndianness());
            return result;
        }

        ledger::core::BigInt BytesReader::readNextBeBigInt(size_t bytes) {
            auto data = read(bytes);
            return BigInt(data.data(), data.size(), false);
        }

        ledger::core::BigInt BytesReader::readNextLeBigInt(size_t bytes) {
            auto data = read(bytes);
            std::reverse(data.begin(), data.end());
            return BigInt(data.data(), data.size(), false);
        }

        uint64_t BytesReader::readNextVarInt() {
            uint8_t size = readNextByte();
            switch (size) {
                case 0xFD:
                    size = 2;
                    break;
                case 0xFE:
                    size = 4;
                    break;
                case 0xFF:
                    size = 8;
                    break;
                default:
                    return size;
            }
            return readNextLeBigInt(size).toUint64();
        }

        std::string BytesReader::readNextVarString() {
            uint64_t length = readNextVarInt();
            return readString(length);
        }

        uint8_t BytesReader::peek() const {
            return _bytes[_cursor];
        }

    }
}<|endoftext|>


<commit_before>#include "cvm.h"

#include "defaults_shared.h"

DabClass &DabVM::define_builtin_class(const std::string &name, dab_class_t class_index,
                                      dab_class_t superclass_index)
{
    DabClass klass;
    klass.index            = class_index;
    klass.name             = name;
    klass.builtin          = true;
    klass.superclass_index = superclass_index;
    classes[class_index]   = klass;
    return classes[class_index];
}

void DabVM::predefine_default_classes()
{
    fprintf(stderr, "vm: predefine default classes\n");

    define_builtin_class("Object", CLASS_OBJECT);
    define_builtin_class("String", CLASS_STRING);
    define_builtin_class("Fixnum", CLASS_FIXNUM);
    define_builtin_class("Boolean", CLASS_BOOLEAN);
    define_builtin_class("NilClass", CLASS_NILCLASS);
    define_builtin_class("Array", CLASS_ARRAY);
    define_builtin_class("Uint8", CLASS_UINT8, CLASS_FIXNUM);
    define_builtin_class("Uint16", CLASS_UINT16, CLASS_FIXNUM);
    define_builtin_class("Uint32", CLASS_UINT32, CLASS_FIXNUM);
    define_builtin_class("Uint64", CLASS_UINT64, CLASS_FIXNUM);
    define_builtin_class("Int8", CLASS_INT8, CLASS_FIXNUM);
    define_builtin_class("Int16", CLASS_INT16, CLASS_FIXNUM);
    define_builtin_class("Int32", CLASS_INT32, CLASS_FIXNUM);
    define_builtin_class("Int64", CLASS_INT64, CLASS_FIXNUM);
    define_builtin_class("Method", CLASS_METHOD);
    define_builtin_class("IntPtr", CLASS_INTPTR);
    define_builtin_class("ByteBuffer", CLASS_BYTEBUFFER);
    define_builtin_class("LiteralString", CLASS_LITERALSTRING, CLASS_STRING);
}

void DabVM::define_default_classes()
{
    fprintf(stderr, "vm: define default classes\n");

    auto &object_class = get_class(CLASS_OBJECT);
    object_class.add_static_reg_function("new", [this](DabValue self, std::vector<DabValue>) {
        auto arg = self;
        assert(arg.data.type == TYPE_CLASS);
        auto instance = arg.create_instance();
        cinstcall(instance, "__construct");
        return instance;
    });
    object_class.add_reg_function(
        "class", [](DabValue self, std::vector<DabValue>) { return self.get_class(); });
    object_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.print_value();
    });
    object_class.add_reg_function("__construct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("__destruct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("is", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        return arg0.is_a(arg1.get_class());
    });
    object_class.add_static_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.class_name();
    });
    object_class.add_static_reg_function("==", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_CLASS);
        assert(arg1.data.type == TYPE_CLASS);
        return DabValue(arg0.data.fixnum == arg1.data.fixnum);
    });

    auto &string_class = get_class(CLASS_STRING);
    string_class.add_reg_function("upcase", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto s = self.string();
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    });
    string_class.add_reg_function("length", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     s = self.string();
        DabValue ret(CLASS_INT32, (int)s.size());
        return ret;
    });
    string_class.add_reg_function("[]", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_FIXNUM);
        auto s   = self.string();
        auto n   = arg.data.fixnum;
        return DabValue(s.substr(n, 1));
    });
    string_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = $VM->cast(args[0], CLASS_STRING);
        auto s0   = arg0.string();
        auto s1   = arg1.string();
        return DabValue(s0 + s1);
    });
    string_class.add_static_reg_function("new", [](DabValue, std::vector<DabValue> args) {
        auto argc = args.size();
        assert(argc <= 2);
        DabValue ret_value;
        ret_value.data.type = TYPE_STRING;
        if (argc == 2)
        {
            auto        arg1   = $VM->cast(args[0], CLASS_BYTEBUFFER);
            auto        arg2   = $VM->cast(args[1], CLASS_FIXNUM);
            const auto &buffer = arg1.bytebuffer();
            const auto  length = arg2.data.fixnum;
            if (length)
            {
                ret_value.data.legacy_string = std::string((const char *)&buffer[0], length);
            }
        }
        else if (argc == 1)
        {
            ret_value.data.legacy_string = args[0].string();
        }
        return ret_value;
    });
    string_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self;
    });
    DAB_MEMBER_EQUALS_OPERATORS(string_class, CLASS_STRING, .string());
    DAB_MEMBER_COMPARE_OPERATORS(string_class, CLASS_STRING, .string());

    auto &fixnum_class = get_class(CLASS_FIXNUM);
    fixnum_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() <= 1);
        auto     klass = self;
        DabValue ret_value;
        ret_value.data.type   = TYPE_FIXNUM;
        ret_value.data.fixnum = 0;
        if (args.size() == 1)
        {
            auto arg = args[0];
            assert(arg.data.type == TYPE_FIXNUM);
            ret_value.data.fixnum = arg.data.fixnum;
        }
        return ret_value;
    });
    DAB_MEMBER_NUMERIC_OPERATORS(fixnum_class, CLASS_FIXNUM, uint64_t, .data.fixnum);

    define_default_classes_int();

    auto &intptr_class = get_class(CLASS_INTPTR);
    intptr_class.add_reg_function("fetch_int32", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     ptr   = self.data.intptr;
        auto     iptr  = (int32_t *)ptr;
        auto     value = *iptr;
        DabValue ret(CLASS_INT32, value);
        return ret;
    });

    auto &boolean_class = get_class(CLASS_BOOLEAN);
    DAB_MEMBER_EQUALS_OPERATORS(boolean_class, CLASS_BOOLEAN, .data.boolean);

    auto &array_class = get_class(CLASS_ARRAY);
    array_class.add_reg_function("count", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        return (uint64_t)self.array().size();
    });
    array_class.add_reg_function("shift", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        if (a.size() == 0)
        {
            return DabValue(nullptr);
        }
        else
        {
            auto ret = a[0];
            a.erase(a.begin());
            return ret;
        }
    });
    array_class.add_reg_function("insert", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = args[0];
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        a.push_back(arg);
        return nullptr;
    });
    array_class.add_reg_function("[]", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            return DabValue(nullptr);
        else
            return a[n];
    });
    array_class.add_function("[]=", [this](size_t n_args, size_t n_ret, void *blockaddr) {
        assert(blockaddr == 0);
        assert(n_args == 3);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg2 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
        {
            fprintf(stderr, "vm: index outside of array bounds.\n");
            exit(1);
        }
        else
        {
            a[n] = arg2;
            stack.push_value(nullptr);
        }
    });
    array_class.add_reg_function("join", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.array();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            auto val = cinstcall(a[i], "to_s");
            ret += val.string();
        }
        return ret;
    });
    array_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto inner = cinstcall(self, "join");
        return std::string("[" + inner.string() + "]");
    });
    array_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_ARRAY);
        return $VM->merge_arrays(self, arg);
    });

    auto &method_class = get_class(CLASS_METHOD);
    method_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return std::string("@method(" + self.string() + ")");
    });

    auto &bytebuffer_class = get_class(CLASS_BYTEBUFFER);
    bytebuffer_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto klass = self;
        assert(klass.data.type == TYPE_CLASS);

        auto instance = klass.create_instance();

        auto _size = $VM->cast(args[0], CLASS_FIXNUM);
        auto size  = _size.data.fixnum;
        instance.bytebuffer().resize(size);
        return instance;
    });
    bytebuffer_class.add_reg_function("[]", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            return DabValue(nullptr);
        else
            return DabValue(CLASS_UINT8, a[n]);
    });
    bytebuffer_class.add_reg_function("[]=", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 2);
        auto arg0 = self;
        auto arg1 = args[0];
        auto arg2 = args[1];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n >= 0 && n < (int64_t)a.size())
        {
            a[n] = $VM->cast(arg2, CLASS_UINT8).data.num_uint8;
        }
        return nullptr;
    });
    bytebuffer_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.bytebuffer();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            char string[32];
            sprintf(string, "%d", (int)a[i]);
            ret += string;
        }
        return "[" + ret + "]";
    });
}
<commit_msg>vm: registerify Array.[]=<commit_after>#include "cvm.h"

#include "defaults_shared.h"

DabClass &DabVM::define_builtin_class(const std::string &name, dab_class_t class_index,
                                      dab_class_t superclass_index)
{
    DabClass klass;
    klass.index            = class_index;
    klass.name             = name;
    klass.builtin          = true;
    klass.superclass_index = superclass_index;
    classes[class_index]   = klass;
    return classes[class_index];
}

void DabVM::predefine_default_classes()
{
    fprintf(stderr, "vm: predefine default classes\n");

    define_builtin_class("Object", CLASS_OBJECT);
    define_builtin_class("String", CLASS_STRING);
    define_builtin_class("Fixnum", CLASS_FIXNUM);
    define_builtin_class("Boolean", CLASS_BOOLEAN);
    define_builtin_class("NilClass", CLASS_NILCLASS);
    define_builtin_class("Array", CLASS_ARRAY);
    define_builtin_class("Uint8", CLASS_UINT8, CLASS_FIXNUM);
    define_builtin_class("Uint16", CLASS_UINT16, CLASS_FIXNUM);
    define_builtin_class("Uint32", CLASS_UINT32, CLASS_FIXNUM);
    define_builtin_class("Uint64", CLASS_UINT64, CLASS_FIXNUM);
    define_builtin_class("Int8", CLASS_INT8, CLASS_FIXNUM);
    define_builtin_class("Int16", CLASS_INT16, CLASS_FIXNUM);
    define_builtin_class("Int32", CLASS_INT32, CLASS_FIXNUM);
    define_builtin_class("Int64", CLASS_INT64, CLASS_FIXNUM);
    define_builtin_class("Method", CLASS_METHOD);
    define_builtin_class("IntPtr", CLASS_INTPTR);
    define_builtin_class("ByteBuffer", CLASS_BYTEBUFFER);
    define_builtin_class("LiteralString", CLASS_LITERALSTRING, CLASS_STRING);
}

void DabVM::define_default_classes()
{
    fprintf(stderr, "vm: define default classes\n");

    auto &object_class = get_class(CLASS_OBJECT);
    object_class.add_static_reg_function("new", [this](DabValue self, std::vector<DabValue>) {
        auto arg = self;
        assert(arg.data.type == TYPE_CLASS);
        auto instance = arg.create_instance();
        cinstcall(instance, "__construct");
        return instance;
    });
    object_class.add_reg_function(
        "class", [](DabValue self, std::vector<DabValue>) { return self.get_class(); });
    object_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.print_value();
    });
    object_class.add_reg_function("__construct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("__destruct", [](DabValue self, std::vector<DabValue> args) {
        (void)self;
        assert(args.size() == 0);
        return nullptr;
    });
    object_class.add_reg_function("is", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        return arg0.is_a(arg1.get_class());
    });
    object_class.add_static_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self.class_name();
    });
    object_class.add_static_reg_function("==", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_CLASS);
        assert(arg1.data.type == TYPE_CLASS);
        return DabValue(arg0.data.fixnum == arg1.data.fixnum);
    });

    auto &string_class = get_class(CLASS_STRING);
    string_class.add_reg_function("upcase", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto s = self.string();
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    });
    string_class.add_reg_function("length", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     s = self.string();
        DabValue ret(CLASS_INT32, (int)s.size());
        return ret;
    });
    string_class.add_reg_function("[]", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_FIXNUM);
        auto s   = self.string();
        auto n   = arg.data.fixnum;
        return DabValue(s.substr(n, 1));
    });
    string_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = $VM->cast(args[0], CLASS_STRING);
        auto s0   = arg0.string();
        auto s1   = arg1.string();
        return DabValue(s0 + s1);
    });
    string_class.add_static_reg_function("new", [](DabValue, std::vector<DabValue> args) {
        auto argc = args.size();
        assert(argc <= 2);
        DabValue ret_value;
        ret_value.data.type = TYPE_STRING;
        if (argc == 2)
        {
            auto        arg1   = $VM->cast(args[0], CLASS_BYTEBUFFER);
            auto        arg2   = $VM->cast(args[1], CLASS_FIXNUM);
            const auto &buffer = arg1.bytebuffer();
            const auto  length = arg2.data.fixnum;
            if (length)
            {
                ret_value.data.legacy_string = std::string((const char *)&buffer[0], length);
            }
        }
        else if (argc == 1)
        {
            ret_value.data.legacy_string = args[0].string();
        }
        return ret_value;
    });
    string_class.add_reg_function("to_s", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return self;
    });
    DAB_MEMBER_EQUALS_OPERATORS(string_class, CLASS_STRING, .string());
    DAB_MEMBER_COMPARE_OPERATORS(string_class, CLASS_STRING, .string());

    auto &fixnum_class = get_class(CLASS_FIXNUM);
    fixnum_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() <= 1);
        auto     klass = self;
        DabValue ret_value;
        ret_value.data.type   = TYPE_FIXNUM;
        ret_value.data.fixnum = 0;
        if (args.size() == 1)
        {
            auto arg = args[0];
            assert(arg.data.type == TYPE_FIXNUM);
            ret_value.data.fixnum = arg.data.fixnum;
        }
        return ret_value;
    });
    DAB_MEMBER_NUMERIC_OPERATORS(fixnum_class, CLASS_FIXNUM, uint64_t, .data.fixnum);

    define_default_classes_int();

    auto &intptr_class = get_class(CLASS_INTPTR);
    intptr_class.add_reg_function("fetch_int32", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto     ptr   = self.data.intptr;
        auto     iptr  = (int32_t *)ptr;
        auto     value = *iptr;
        DabValue ret(CLASS_INT32, value);
        return ret;
    });

    auto &boolean_class = get_class(CLASS_BOOLEAN);
    DAB_MEMBER_EQUALS_OPERATORS(boolean_class, CLASS_BOOLEAN, .data.boolean);

    auto &array_class = get_class(CLASS_ARRAY);
    array_class.add_reg_function("count", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        return (uint64_t)self.array().size();
    });
    array_class.add_reg_function("shift", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        if (a.size() == 0)
        {
            return DabValue(nullptr);
        }
        else
        {
            auto ret = a[0];
            a.erase(a.begin());
            return ret;
        }
    });
    array_class.add_reg_function("insert", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = args[0];
        assert(self.data.type == TYPE_ARRAY);
        auto &a = self.array();
        a.push_back(arg);
        return nullptr;
    });
    array_class.add_reg_function("[]", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            return DabValue(nullptr);
        else
            return a[n];
    });
    array_class.add_reg_function("[]=", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 2);
        auto arg0 = self;
        auto arg1 = args[0];
        auto arg2 = args[1];
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.array();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
        {
            fprintf(stderr, "vm: index outside of array bounds.\n");
            exit(1);
        }
        else
        {
            a[n] = arg2;
        }
        return nullptr;
    });
    array_class.add_reg_function("join", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.array();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            auto val = cinstcall(a[i], "to_s");
            ret += val.string();
        }
        return ret;
    });
    array_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        auto inner = cinstcall(self, "join");
        return std::string("[" + inner.string() + "]");
    });
    array_class.add_reg_function("+", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg = $VM->cast(args[0], CLASS_ARRAY);
        return $VM->merge_arrays(self, arg);
    });

    auto &method_class = get_class(CLASS_METHOD);
    method_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        return std::string("@method(" + self.string() + ")");
    });

    auto &bytebuffer_class = get_class(CLASS_BYTEBUFFER);
    bytebuffer_class.add_static_reg_function("new", [](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto klass = self;
        assert(klass.data.type == TYPE_CLASS);

        auto instance = klass.create_instance();

        auto _size = $VM->cast(args[0], CLASS_FIXNUM);
        auto size  = _size.data.fixnum;
        instance.bytebuffer().resize(size);
        return instance;
    });
    bytebuffer_class.add_reg_function("[]", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 1);
        auto arg0 = self;
        auto arg1 = args[0];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= (int64_t)a.size())
            return DabValue(nullptr);
        else
            return DabValue(CLASS_UINT8, a[n]);
    });
    bytebuffer_class.add_reg_function("[]=", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 2);
        auto arg0 = self;
        auto arg1 = args[0];
        auto arg2 = args[1];
        assert(arg0.data.type == TYPE_BYTEBUFFER);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.bytebuffer();
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n >= 0 && n < (int64_t)a.size())
        {
            a[n] = $VM->cast(arg2, CLASS_UINT8).data.num_uint8;
        }
        return nullptr;
    });
    bytebuffer_class.add_reg_function("to_s", [this](DabValue self, std::vector<DabValue> args) {
        assert(args.size() == 0);
        std::string ret;
        auto &      a = self.bytebuffer();
        for (size_t i = 0; i < a.size(); i++)
        {
            if (i)
                ret += ", ";
            char string[32];
            sprintf(string, "%d", (int)a[i]);
            ret += string;
        }
        return "[" + ret + "]";
    });
}
<|endoftext|>