协程演示源码

2023-12-10

这是一个程序示例,其中协程确实有助于简化 该算法-恕我直言,否则很难实现。 我还尝试为演示选择一个有用的任务 - 该实用程序将 一个二进制文件到一系列 A-Z 符号(以及后面),没有任何显着的 冗余,并且它能够处理任何指定的字母表 (参见 M.Init 行)。基本上它类似于广义的 base64。 该代码经过测试并可与 MSC、IntelC 和 gcc/mingw 配合使用。

更新:该算法基于精确的算术编码,因此默认情况下它不是单行的。 可以通过使用 putc/getc 文件 i/o 将其切成两半 (因此仅保留修改后的范围编码器类和 do_process() ), 但它会非常有限(例如,不适用于解码 内存块或网络流)。 实际上协程在这里是作为速度优化使用的,它的 这篇文章的重点。 不幸的是,我没有任何更简单的应用程序来正确演示这一点 - 我可以编写一个上下文建模压缩器,但这大约是 100 线路更多。

问题:
1) 如何用正确的 C++ 代码替换 INCLUDE_PROCESS_TEMPLATE 宏?
2)有没有办法在没有协程的情况下实现这一点?
(但仍然使用内存中编码和缓冲文件 I/O)
3)有任何修复/改进吗?

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <setjmp.h>
#define NOINLINE __declspec(noinline)

typedef unsigned int   uint;
typedef unsigned char  byte;
typedef unsigned long long int qword;

enum{ STKPAD=1<<16 };
struct coroutine {
  volatile int   state;
  volatile byte* inpptr;
  volatile byte* inpbeg;
  volatile byte* inpend;
  volatile byte* outptr;
  volatile byte* outbeg;
  volatile byte* outend;
  jmp_buf PointA, PointB;
  void yield( int value ) { if( setjmp(PointB)==0 ) { state=value; longjmp(PointA,value); } }
  void chkinp( void ) { if( inpptr>=inpend ) yield(1), inpptr=*&inpptr; }
  void chkout( void ) { if( outptr>=outend ) yield(2); }
  template <int f> byte get( void ) { if( f ) chkinp(); return *inpptr++; }
  template <int f> void put( uint c ) { *outptr++ = c; if( f ) chkout(); }
  void coro_init( void ) { inpptr=inpbeg=inpend=0; outptr=outbeg=outend=0; state=0; }
  void addinp( byte* inp,uint inplen ) { inpbeg=inpptr=inp; inpend=&inp[inplen]; }
  void addout( byte* out,uint outlen ) { outbeg=outptr=out; outend=&out[outlen]; }
};

#define INCLUDE_PROCESS_TEMPLATE \
NOINLINE void call_do_process() { byte stktmp[STKPAD]; state=ptrdiff_t(stktmp); do_process(); } \
int coro_process( void ) { if( setjmp(PointA)==0 ) if( state ) longjmp(PointB,3); else call_do_process(); return state; } 

struct Rangecoder_SH1x : coroutine {
  enum { SCALElog=15, SCALE=1<<SCALElog };
  enum { NUM=4, sTOP=0x01000000U, Thres=0xFF000000U };
  uint f_decode; // 0=encode, 1=decode;
  uint range, Cache, FFNum;
  union {
    struct { uint low; uint Carry; };
    qword lowc;
    uint  code; 
  };
  uint rc_BProcess( uint freq, uint bit ) { 
    uint rnew = (range>>SCALElog)*freq;
    if( f_decode ) bit = (code>=rnew);
    range = ((range-rnew-rnew)&(-bit)) + rnew;
    rnew &= -bit;
    if( f_decode ) code-=rnew; else lowc+=rnew;
    if( f_decode ) while( range<sTOP ) range<<=8, (code<<=8)+=get<1>();
    else while( range<sTOP ) range<<=8, ShiftLow();
    return bit;
  }
  void ShiftLow( void ) {
    if( low<Thres || Carry ) {
      put<1>( Cache+Carry );
      for(; FFNum!=0; FFNum-- ) put<1>( Carry-1 );
      Cache=low>>24; Carry=0;
    } else FFNum++;
    low<<=8;
  }
  void rc_Init( int DECODE ) {
    f_decode=DECODE; range=-1; lowc=FFNum=Cache=0;
    if( f_decode ) for(int _=0; _<NUM+0; _++) (code<<=8)+=get<1>(); 
  }
};

struct Model : Rangecoder_SH1x {
  uint DECODE, f_quit;
  enum{ lCNUM=8, CNUM=1<<lCNUM, ROWSIZE=80 };
  uint count[2*CNUM];
  enum{ inpbufsize=1<<16, outbufsize=1<<16 };
  byte inpbuf[inpbufsize], outbuf[outbufsize];

  void Init( const char* s ) {
    uint i,j;
    uint (&p)[CNUM] = (uint(&)[CNUM])count[CNUM];
    for( i=0; i<2*CNUM; i++) count[i]=0;
    for( i=0; s[i]; i++ ) p[byte(s[i])]++;
    for( j=0; j<lCNUM; j++ ) for( i=(CNUM>>j); i<((CNUM+CNUM)>>j); i++ ) count[i>>1] += count[i];
  }

  INCLUDE_PROCESS_TEMPLATE
  void do_process( void ) {
    uint i,j;
    rc_Init(1-DECODE);
    for( i=0; !f_quit; i++ ) {
      uint c=0, ctx=1;
      if( DECODE ) do c=get<1>(); while( c==10 );
      for( j=lCNUM-1; j!=-1; j-- ) {
        uint freq = count[ctx*2+0]*SCALE/(count[ctx*2+0]+count[ctx*2+1]);
        ctx += ctx + ((freq==0) ? 1 : (freq==SCALE) ? 0 : rc_BProcess(freq,(c>>j)&1));
      }
      if( !DECODE ) put<1>(ctx), (((i+1)%ROWSIZE==0)?put<1>(10),0:0);
    }
    yield(0);
  }

  void ProcessFile( uint Mode, FILE* f, FILE* g ) {
    volatile uint r; volatile qword g_len=0; uint f_len=0;
    DECODE=Mode; f_quit=0;
    if( DECODE ) addout( (byte*)&g_len, sizeof(f_len)+1 ), r=1;
    else f_len=filelength(fileno(f)), addinp( (byte*)&f_len, sizeof(f_len) ),addout(0,0), r=2;
    do {
      if( r==1 ) {
        uint l = fread( inpbuf, 1, inpbufsize, f );
        if( l>0 ) {
          addinp( inpbuf, l );
        } else {
          if( inpbeg==inpbuf+1 ) f_quit=1;
          memset( inpbuf, 0x80, inpbufsize );
          addinp( inpbuf+1, 5 ); 
        }
      } else if( r==2 ) {
        if( outbeg==outbuf ) fwrite( outbuf, 1, outptr-outbeg, g ); else g_len>>=8;
        addout( outbuf, outbufsize );
      }
      r = coro_process(); 
    } while(r);
    fwrite( outbuf, 1,outptr-outbuf, g ); // flush
    if( DECODE==0 ) fputc( 10, g ); else fflush(g), chsize( fileno(g), g_len );
  }

} M;

int main( int argc, char** argv ) {
  if( argc<4 ) return 1;
  int DECODE = argv[1][0]=='d';
  FILE* f = fopen( argv[2], "rb" ); if( f==0 ) return 2;
  FILE* g = fopen( argv[3], "wb" ); if( g==0 ) return 3;
  M.Init( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
  M.ProcessFile( DECODE, f, g );
}

只是为了笑,这里是我如何处理仅对任意字母进行编码/解码的部分的粗略想法。正如所承诺的,实际的编码/解码大约是十几行代码。整体大小较大,很大程度上是因为我自始至终都使用了模板,因此数字可以是任意整数类型,字符可以是任意字符类型,并且它都使用迭代器,因此它可以读取/写入任意集合(流、字符串流、向量等)

编辑:修改代码以从文件读取输入并将输出写入文件(并修复一两个小错误):

#include <iterator>
#include <iostream>
#include <string>
#include <limits>
#include <vector>
#include <fstream>
#include <time.h>
#include <math.h>
#include <stdlib.h>

template <class intT>
intT log2(intT input) { 
    return intT(log10((double)input) / log10(2.0));
}

template <class intT>
class coder { 
    std::string alphabet;   
    size_t range;
    unsigned ratio;
public:
    coder(std::string const &alpha) : alphabet(alpha), range(alpha.size()) {
        ratio = ceil(double(log2(std::numeric_limits<intT>::max())/log2(range)));
    }

    template <class inIt, class outIt>
    void encode(inIt begin, inIt end, outIt out) { 
        while (begin != end) {
            intT val = *begin++;
            for (int i=0; i<ratio; i++) {
                *out++ = alphabet[val % range];
                val /= range;
            }
        }
    }

    template <class inIt, class outIt>
    void decode(inIt begin, inIt end, outIt out) { 
        while (begin != end) {
            int temp = 0;
            for (int i=0; i<ratio; i++)
                temp += alphabet.find(*begin++) * pow((double)range, i);
            *out++ = temp;
        }
    }
};

int main(int argc, char **argv) {
    if (argc != 3) {
        std::cerr << "Usage: encode <infile> <outfile>\n";
        return EXIT_FAILURE;
    }

    coder<unsigned> enc("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    std::ifstream in(argv[1], std::ios::binary);
    std::ofstream out(argv[2]);
    clock_t start = clock();
    enc.encode(std::istream_iterator<char>(in), 
        std::istream_iterator<char>(), 
        std::ostream_iterator<char>(out, ""));
    clock_t stop = clock();
    std::cerr << "Processing time: " << double(stop-start)/CLOCKS_PER_SEC << "\n";
    return 0;
}

至少目前,我忽略了算术编码部分,但它应该(至少在我看来)遵循类似的结构,这样你就可以很容易地将事物或多或少任意地串在一起。

就比较速度和大小而言,请记住,这根本不进行任何压缩,而只是进行 baseX 编码——在这种情况下,尝试与进行压缩的东西进行比较没有任何实际意义(除了,例如,了解压缩的效果如何——但如果它确实有效,它显然会产生更小的输出)。

就可执行文件的大小而言,我只能说 gcc 生成大型可执行文件从来没有让我感到惊讶。使用 MS VC++,我获得了上述代码的 9,728 字节的可执行文件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协程演示源码 的相关文章

  • 如何声明一个变量来存储通过引用返回的对象?

    C 参考仍然让我感到困惑 假设我有一个创建类型对象的函数 方法Foo并通过引用返回它 我假设如果我想返回该对象 它不能是在堆栈上分配的局部变量 所以我必须在堆上分配它new Foo makeFoo Foo f new Foo return
  • 如何从 Azure Key Vault KeyBundle 创建 X509Certificate2 对象

    我正在使用 Azure Key Vault 来保护我们的密钥和机密 但我不确定如何使用通过 net SDK 检索到的 KeyBundle 如何创建 X509Certificate2 对象 当您在 KeyVault 中导入 创建证书时 会创建
  • 从多播数据包中获取发送者 ip

    如何获取组播 UDP 数据包发送者的 IP 当前代码以同步 阻塞方式设置 参见下面的注释 这是代码 private void receive string mcastGroup SetMcastGroup s new Socket Addr
  • 全球化自定义数字格式 - 可变小数点

    我正在尝试更改公司应用程序中现有的数字格式 以使其对国际用户更具可读性 这是一个股票交易应用程序 因此大多数股票价格的数字精确到小数点后 2 位 例如 gt 17 23 我们还可以得到精确到小数点后 4 位的价格变动 因此细价股票可能是 0
  • 用于在 n LSBits 之后清除 m 位的掩码

    我在一次采访中被问到这个问题 要清除 16 位整数的 n 位之后的 m 位 假设数字是 10010010010100101 清除 LSBit 中 5 位后的三位 之前 1001100111011001 之后 1001100100011001
  • 使用顶点缓冲区对象 (VBO) 渲染 Kinect 点云

    我正在尝试制作一个动态点云可视化工具 使用 Kinect 传感器每帧更新这些点 为了抓取帧 我使用 OpenCV 和 GLUT 来显示 OpenCV API 对于点 xyz 位置返回 640 x 480 float 对于 rgb 颜色数据返
  • C++ lambda 构造函数参数可以捕获构造变量吗?

    下列compiles 但是是否存在任何悬而未决的参考问题 class Foo Foo std function
  • 从 gdb 设置 std::string 变量值?

    是否有可能 当调试器在断点处停止时 修改 std string 变量的值 而不需要采取诸如调整当前缓冲区的内存映像之类的黑客手段 例如类似于 set var mystring hello world 试试这个 经过测试并且对我有用 call
  • 如何在Windows窗体中平滑地重新绘制Panel

    如何将面板重漆成光滑的 我正在使用一个使面板无效的计时器 panel1 Invalidate 每 300 毫秒一次 然后panel1 Paint如果我向该面板添加图像 问题是它看起来像是在跳跃 我需要尽可能快地移动其上的一张图像 这是截屏问
  • 如何访问UPnP设备的服务?

    设备 贝尔金 WeMo Switch开发环境 Windows 7 上的 MS VC 2010 我正在尝试使用 Windows 中的 C 枚举 UPnP 设备的服务 我有IUPnPDevice指针并可以访问多个属性 我有IUPnPServic
  • 强名称验证失败

    两台机器 均带有 NET 3 5 和 VS 2008 VC SP1 可再发行组件 单个 exe 使用两个签名的 DLL 一个在 C CLI 中 一个在 C 中 该exe在一台机器上加载并运行良好 另一方面 我在 C 可执行文件上收到 强名称
  • C# 在不使用反射的情况下运行时出现“找不到方法”异常

    我在获得上述异常时遇到问题 我有一个相对简单的结构 分为两个 dll 第一个包含 IEntityService IEntity 和基本实现 第二个包含实际的实现和接口 因此 有一个 IMachine 服务实现了 IEntityService
  • 如何在其他项目中添加NLog类库项目

    我已经用 C 创建了一个控制台项目 在该项目中我使用 NLog 进行日志记录 当我运行该项目时 它成功登录到多个目标 例如控制台 文件 EventLog 以及 Sentinal 但是 当我将此项目作为类库并尝试添加对另一个项目的引用时 它不
  • 指向虚拟成员函数的指针。它是如何工作的?

    考虑以下 C 代码 class A public virtual void f 0 int main void A f A f 如果我不得不猜测 我会说 A f 在这种情况下意味着 A 的 f 实现的地址 因为指向常规成员函数和虚拟成员函数
  • 代码契约确保 ReSharperExternalAnnotations

    有谁知道如何在 ReSharperExternalAnnotations 中添加 Code Contracts Ensures 它在最新的 v7 1 3 和最新的 v8 EAP 中都不存在 在任何自定义 xml 中也不存在 具体来说 它应该
  • 隐式构造函数和默认构造函数有什么区别?

    这是非常微不足道的 但是捷克语 我的母语 不区分隐式和默认 所以我对一些捷克语翻译感到困惑 隐式和默认构造函数或构造函数调用之间有什么区别 struct Test Test int n 0 您能用这些术语描述以下语句的作用吗 Test t1
  • 隐藏 AppBar 中的省略号

    当您在 UWP 应用中创建 AppBar 或 CommandBar 时 控件侧面附近总会隐藏一个省略号 如下所示 我不想在我的应用程序中使用它 但我没有在其中找到任何方法 属性AppBar这会帮助我摆脱它 这应该是可能的 因为许多默认的 W
  • 空序列的算术平均值是多少?

    免责声明 不 我没有找到任何明显的答案 这与我的预期相反 在寻找代码示例时 算术平均值 我可以通过谷歌找到的前几个例子似乎是这样定义的 空序列生成的平均值为0 0 eg here https rosettacode org wiki Ave
  • 如何在 MVC 中点击链接的主视图中渲染部分视图?

    我有像下面这样的控制器操作方法将从数据库返回所有详细信息 public ActionResult Index BusDataContext db new BusDataContext List
  • 删除重复项并将列表放入列表框中

    这是一项大学作业 我对其中的一部分遇到了问题 这是代码 namespace Assignment 1 public partial class Classifier System Web UI Page We are using a web

随机推荐

  • 标题大小写是一个包含一个或多个姓氏的字符串,同时处理带有撇号的姓名

    我想标准化用户提供的字符串 我希望姓名的第一个字母大写 如果他们输入了两个姓氏 则将名字和第二个名字大写 例如 如果有人输入 marriedname maidenname 它会将其转换为Marriedname Maidenname如果有两个
  • 关于根据年份生成年龄变量的思考

    多年来我一直试图创建一个虚拟变量 目前 我的数据有每个观察的出生日期和程序开始日期 我已经能够创建一个以天为单位测量个人年龄的变量 但我实际上正在寻找的是一个变量 age join date 它告诉我以下内容 Individual birt
  • Haskell:列表、数组、向量、序列

    我正在学习 Haskell 并阅读了几篇有关 Haskell 列表和 插入您的语言 数组的性能差异的文章 作为一名学习者 我显然只是使用列表 甚至没有考虑性能差异 我最近开始调查并发现 Haskell 中有许多可用的数据结构库 有人可以在不
  • URL 中 Hash(#) 的使用

    我想知道除了作为 URL 中的锚点之外 哈希还有其他用途吗 我在这里读到了它获取完整的 url 包括哈希后的查询字符串 客户端的状态信息是什么 请帮忙 哈希也可用于单页面应用程序 因此您可以使用哈希作为从一个页面导航到另一个页面的方式 而不
  • C# 使用 LINQ 选择行的最大 ID

    我有一个面包屑表 我想返回最近插入的行 在 SQL 中它将是MAX 函数 但不确定如何在 LINQ 中执行等效操作 基本上我想选择具有最高的行BreadCrumbID WHERE ProjectID 49 这是我现在的查询 它将选择所有行W
  • Java 中的并行计算 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 如何在 Java 中使用并行 或者我使用普通线程 阅读Java并发教程 创建多个线程来为您完成工作
  • Java中根据天数获取日期

    简单的问题 但令人惊讶的是谷歌对此几乎没有什么了解 我有number of days从今年1月1日开始 我怎样才能将其转换为date在Java中 你可以简单地使用SimpleDateFormat转换String to Date 图案D可以用
  • 如何将 int 转换为 NSString?

    我想转换一个int to a NSString在目标 C 中 我怎样才能做到这一点 基元可以转换为对象 表达 所以shortest方法就是转变int to NSNumber并选取字符串表示形式stringValue method NSStr
  • 泛型集合“无法实例化类型 ArrayList

    根据我读到的内容 我认为这是不可能的 但我想确定一下 我有课OpDTO和其他几个 DTO extends OpDTO 然后 我想要一种方法从这些子 DTO 的列表中仅提取某些元素 并在另一个列表中返回提取的元素 public List
  • komodo edit 7.1 在 php 模式下无法识别 html5 标签

    标题已经很说明性了 在 php 模式下 komodo edit 假定 html4 并在使用像文章 时间 部分这样的 html5 标签时引发错误 这可能会很麻烦 因为它可能会覆盖 php 错误 有没有办法来解决这个问题 也许找到了解决方案 首
  • 检测网页上的合成点击

    通过 Javascript 是否可以检测合成点击 不是由人类生成而是使用 JS 或其他自动化工具生成的点击 也许我们可以做这样的事情 document onmousedown function e if typeof e pageX und
  • Cocoapods pod 稳定构建设置

    有没有办法在中添加构建设置cocoapodspod 无需直接更改 Pods 项目或其他自动生成的内容 因此在之后它仍然会存在pod install 具体来说 我需要设置DISABLE MIXPANEL AB DESIGNER 1在 Mixp
  • Yii - “白屏死机”,调试技巧

    我有一个运行 Yii 应用程序的临时服务器 现在出现 死机白屏 我看不到屏幕上输出的任何内容 甚至 查看源代码 时的源代码 在本地相同的代码运行没有任何问题 任何人都可以建议一个在 Yii 应用程序中调试 死机白屏 的好例程吗 在 yii
  • asp.net 会员提供商 Guid userID

    我需要 我认为 获取当前登录的用户 ID 以便我可以更新使用此用户 ID 作为外键的表之一 问题是数据库中的userID与此不匹配 Guid currentUser Guid Membership GetUser ProviderUserK
  • 仅安装较新的框架时应用程序是否会运行

    我似乎找不到我的问题的答案 所以我只是在这里问 假设我有一个为 Net Framework 4 62 构建的应用程序 它可以在只安装了 4 7 的服务器上运行吗 当然除了一些旧的框架 或者我需要安装每个目标框架吗 NET Framework
  • 如何使用 CSS 透视将元素定位在正确的 3D 位置

    我正在尝试找到一种方法来在以给定角度放置的照片元素之上映射元素 笔记本电脑的照片就是一个很好的例子 我想在屏幕顶部映射一个元素 视频 图像或其他 例如循环播放视频等 这个任务看起来很简单 但我发现它非常棘手 因为我找不到如何通过变换 旋转
  • 标签为类别页面 Blogger 中的标题

    我有一个网站 可以在其中显示具有所有相同标签的帖子 有没有办法在显示具有相同标签的所有帖子时将标签作为标题 例如 关于https newsotuniverse blogspot ca search label astrophysicals有
  • Swift 中每次动画迭代后的延迟

    我有一个核心动画 repeatCount被设定为Float infinity 在动画的每次迭代之后 即 每次重复之后 我想要延迟 3 秒 我怎样才能实现这个目标 谢谢 您可以使用function像下面这样做你需要做的事情 func anim
  • 从 Delphi 访问 Android 的 SharedPreferences 类

    我刚刚开始使用 Delphi XE5 进行 Android 开发 并尝试构建一个简单的应用程序 该应用程序需要能够保留一些输入的信息 配置 我已经弄清楚了 Android 类共享首选项可能是最简单的方法 但我不知道如何从 Delphi XE
  • 协程演示源码

    这是一个程序示例 其中协程确实有助于简化 该算法 恕我直言 否则很难实现 我还尝试为演示选择一个有用的任务 该实用程序将 一个二进制文件到一系列 A Z 符号 以及后面 没有任何显着的 冗余 并且它能够处理任何指定的字母表 参见 M Ini